Titanic: Machine Learning from Disaster - 2
A. Geronさんのテキスト第2章の勉強の成果を試そう!
意気込んでとりかかったのはよいが、いきなり、つまづいた。
A. Geronさんのテキストで学んだhousingは、住宅価格を予測するということで、回帰問題、regressionである。
対して、Titanicは、乗客が生存するかどうか予測するという、分類問題、classificationである。
housingは主として数値を扱っていて、唯一のカテゴリーデータocean_proximityは、OneHotEncoderで配列に変換して、回帰問題として扱い、機械学習モデルで扱えるようにした、ということだが、住宅価格の予測に対して、どう作用しているのか、直観的には理解できていない。
分類問題において、数値とカテゴリー(テキスト)はどう扱われているのか。これまでは、明確に意識してこなかったので、今回は、分類問題における数値とテキストの扱い方に注意しながら学習しよう。
データ数は、Titanicが、train:891, test:418、housingがtotal:20640である。つまり、Titanicのデータ数は、housingの6.3%である。
このデータ数が少ないことは、overfittingしやすいことを意味している。
Alexis Cook's Titanic Tutrialでは、
features = ["Pclass", "Sex", "SibSp", "Parch"]
この4つのattributeを使って、RandomForestClassifierを学習させている。
Pclass(等級), SibSup(兄弟または配偶者の人数), Parch(両親または子供の人数)は、整数、Sexは文字列である。
文字列と整数ならOKということかな。
そうではなく、pd.get_dummys( )を使うことによって、自動的に、
Sex_femaleとSex_maleに分けていて、情報量で表現しているようだ。
X = pd.get_dummies(train_data[features])
Pclass SibSp Parch Sex_female Sex_male
0 3 1 0 0 1
1 1 1 0 1 0
2 3 0 0 1 0
3 1 1 0 1 0
4 3 0 0 0 1
分類用のprint(train.columns)機械学習モデルの性能を生かすために、テキストを情報量で表現しなおすこと、数値を、3~10段階くらいにクラス分けして、整数で表現するなどの操作を行なっているようである。
少しコードを拝借してみようかな。
print(train.columns)
Index(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp',
'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'], dtype='object')
print("Percentage of females who survived:", train["Survived"][train["Sex"] == 'female'].value_counts(normalize = True)[1]*100)
Percentage of females who survived: 74.20
print("Percentage of Pclass = 1 who survived:", train["Survived"][train["Pclass"] == 1].value_counts(normalize = True)[1]*100)
Percentage of Pclass = 1 who survived: 62.96
#sort the ages into logical categories
train["Age"] = train["Age"].fillna(-0.5)
bins = [-1, 0, 5, 12, 18, 24, 35, 60, np.inf]
labels = ['Unknown', 'Baby', 'Child', 'Teenager', 'Student', 'Young Adult', 'Adult', 'Senior']
train['AgeGroup'] = pd.cut(train["Age"], bins, labels = labels)
#draw a bar plot of Age vs. survival
sns.barplot(x="AgeGroup", y="Survived", data=train)
plt.show()
年齢を分割して、カテゴリーに変換している。
関係なさそうなattributeは消去
train = train.drop(['Cabin'], axis = 1)
train = train.drop(['Ticket'], axis = 1)
すごいなと思ったのは、Nameから、Titleを抽出して、生存率を調べたり、Titleと年齢の相関から、年齢がNaNとなっている人の年齢をTitleから推定したり・・・。
高いスコアを出している人は、データを隅々まで調べて、生存率との相関をとっていることと、生存率との相関が認められないものは捨てている。最後に、予測精度が高い人は、trainとtestをきちんと切り分けているようにみえる。
Titanicコンペのnotebookに関するdiscussionを読んでいて感じたこと。
グリッドサーチによるハイパーパラメータの最適化ができていない。
アンサンブル学習を利用している人が少ない。
RやC++の使い手が凄い。
まあ、初心者用コンペなので、トップコーダーたちは、あまり顔を出していない。
5月15日:A. Geronさんのテキストの第2章の復習等
housing.head( )
housing.tail( )
housing.info( )
housing["ocean_proximity"].value_counts( )
housing.describe( )
%matplotlib inline
housing.hist(bins=50, figsize=(20,15))
plt.show( )
from sklearn.model_selection import train_test_split
train_set, test_set = train_test_split(housing, test_size=0.2, random_state=42)
housing["income_cat"] = pd.cat(housing["mediun_income"],
bins=[0., 1.5, 3.0, 4.5, 6., np.inf],
lables=[1, 2, 3, 4, 5])
housing["income_cat"].hist( )
from sklearn.model_selection import StratifiedShuffleSplit
split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
for train_index, test_index in split.split(housing, housing["income_cat"]):
strat_train_set = housing.loc[train_index]
strat_test_set = housing.loc[test_index]
strat_test_set["income_cat"].value_counts( ) / len(strat_test_set)
for set_ in (strat_train_set, strat_test_set):
set_.drop("incom_cat", axis=1, inplace=True)
housing = strat_train_set.copy( )
housing.plot(kind="scatter", x="longitude", y="latitude", alpha=0.1)
housing.plot(kind="scatter", x="longitude", y="latitude", alpha=0.4,
s=housing["population"]/100, lable="population", figsize=(10,7),
c="median_house_value", cmap=plt.get_cmap("jet"), colorbar=True,)
plt.legend( )
corr_matrix = housing.corr( )
corr_matrix["median_house_value"].sort_values(ascending=False)
median_house_value 1.000000
median_income 0.687170
total_rooms 0.135231
housing_median_age 0.114220
from pandas.plotting import scatter_matrix
attributes = ["median_house_value", "median_incom", "total_rooms", "housing_median_age]
scatter_matrix(housing[attributes], figsize=(12,8))
housing.plot(kind="scatter", x="median_income", y="median_house_value", alpha=0.1)
# create new attribute
housing["rooms_per_household"] = housing["total_rooms"]/housing["households"]
housing["bedrooms_per_room"] = housing["total_bedrooms"]/housing["total_rooms"]
housing["population_per_household"]=housing["population"]/housing["households"]
# prepare the data
housing = strat_train_set.drop("median_house_value", axis=1) # X_train
housing_lables = strat_train_set["median_house_value"].copy( ) # y_train
# data cleaning
housing.dropna(subset=["total_bedrooms"]) # option 1
housing.drop("total_bedrooms", axis=1) # option 2
median = housing["total_bedrooms"].median( ) # option 3
housing["total_bedrooms"].fillna(median, inplace=True)
# take care of missing values
from sklearn.impute import SimpleImputer
imputer = SimpleImputer(strategy="median")
# median can only computed on numerical attributes
housing_num = housing.drop("ocean_proximity", axis=1)
imputer.fit(housing_num)
X = imputer.transform(housing_num)
# handling text and categorical attributes
housing_cat = housing"ocean_proximity"
from sklearn.preprocessing import OrdinalEncoder
ordinal_encoder = OrdinalEncoder( )
housing_cat_encoded = ordinal_encoder.fit_transform(housing_cat)
from sklearn.preprocessing import OneHotEncoder
cat_encoder = OneHotEncoder( )
housing_cat_1hot = cat_encoder.fit_transform(housing_cat)
# custom transformers
from sklearn.base import BaseEstimator, TransformerMixin
class CombinedAttributesAdder(BaseEstimator, TransformerMixin)
# feature scaling
min-max scaling (many people call this normalization)
# transformation pipelines
# training and evaluating on the training set
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_square_error
from sklearn.tree import DecisionTreeRegressor
# cross-validation
from sklearn.model_selection import cross_val_score
tree_reg = DecisionTreeRegressor( )
scores = cross_val_score(tree_reg, housingprepared, housing_lables,
scoring="neg_mean_squared_error", cv=10)
from sklearn.ensemble import RandomForestRegressor
forest_reg = RnadomForestRegressor( )
forest_scores = cross_val_score(forest_reg, housing_prepared, housing_labels,
scoring="neg_mean_squared_error", cv=10)
# fine-tune
# grid search
おわり