Pandas
をたまに使っていたのですが、毎回ググって調べるのが苦痛になってきたため記事にまとめました。Kaggleを本格的にやろうとしていることがきっかけです。
結構色々書いたのですが、グラフ出力はパターンが多すぎるので良いと思ったものがあれば適宜追加予定です。
環境
記事「UbuntuにpyenvとvenvでPython開発環境構築」に書いた方法で環境構築をしています。記事「Windows PCで機械学習環境を作る方法まとめ」に書いている別方法でもいいと思います(少し古いので間違っている可能性などあり)。
種類 | バージョン | 内容 |
---|---|---|
OS | Ubuntu20.04.01 LTS | 仮想で動かしています |
pyenv | 1.2.24 | 複数Python環境を使うことがあるのでpyenv使っています |
Python | 3.9.2 | pyenv上でpython3.9.2を使っています パッケージはvenvを使って管理しています |
上記環境で、以下のPython追加パッケージを使っています。通常のpipでインストールするだけです。
種類 | バージョン |
---|---|
pandas | 1.2.4 |
matplotlib | 3.4.1 |
jupyter lab | 3.0.14 |
前提
データはKaggle Titanicのtrain.csvを使っています。
各ライブラリのエイリアスは以下のように定義しています。
import pandas as pd
import matplotlib.pyplot as plt
ファイル読込
read_csv
を使います。特筆することもないですが、いろいろオプションがありますので公式APIを参照ください。read_table
もありますが、デフォルトの区切り文字が違うだけのようです(記事「pandasでcsv/tsvファイル読み込み(read_csv, read_table)」参照)。
train_data = pd.read_csv("/kaggle/input/titanic/train.csv")
read_table
とread_csv
は過去に言語処理100本ノックでも多用しました。
-
12本目: 1列目をcol1.txtに,2列目をcol2.txtに保存:
header=None, usecols=[0, 1]
を使って、ヘッダ行無視と行指定 -
31本目: 動詞:
-
sep
: 区切り文字指定 -
names
: index名指定 -
skiprows
: スキップ行指定 -
skipfooter
: スキップフッタ行指定 -
engine
: エンジン指定(確かskipfooter
使うとenginge
をpythonにする必要あり)
-
ファイル読込時にやること
概要出力: info
ファイル読込時にinfo
関数で概要を出力します。型がわかったり、欠損値がわかったりと便利です。
train_data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 PassengerId 891 non-null int64
1 Survived 891 non-null int64
2 Pclass 891 non-null int64
3 Name 891 non-null object
4 Sex 891 non-null object
5 Age 714 non-null float64
6 SibSp 891 non-null int64
7 Parch 891 non-null int64
8 Ticket 891 non-null object
9 Fare 891 non-null float64
10 Cabin 204 non-null object
11 Embarked 889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB
統計情報出力: describe
describe
関数で数値系項目は統計情報を出力できます。
train_data.describe()
データ加工
コピー: copy
元データを保存しておきたい場合は、コピーして新しいDataFrameに対して加工します。
train_new = train_data.copy()
値のカウント: value_counts
value_counts
を使って値の件数カウントをします。デフォルトでソートONなので、OFFにするオプションをよく使います。
print(train_data.Pclass.value_counts())
print('----')
print(train_data.Pclass.value_counts(sort=False))
3 491
1 216
2 184
Name: Pclass, dtype: int64
----
1 216
2 184
3 491
Name: Pclass, dtype: int64
文字列検索・抽出系
文字列検索・抽出はよくやると思うので、簡単に書いておきます。詳しくは、以下の2つの記事で書きました。
列に対して文字列部分一致検索
str.containts
を使って列に対して文字列部分一致検索をします。今回は使っていませんが、正規表現も使えます。
※記事「ゼロから覚えるPython正規表現の基本とTips」に正規表現について以前まとめました。
# 文字列の部分一致検索
print(train_data[train_data.Name.str.contains('Mr.', regex=False)].Name)
0 Braund, Mr. Owen Harris
4 Allen, Mr. William Henry
5 Moran, Mr. James
6 McCarthy, Mr. Timothy J
12 Saundercock, Mr. William Henry
...
881 Markun, Mr. Johann
883 Banfield, Mr. Frederick James
884 Sutehall, Mr. Henry Jr
889 Behr, Mr. Karl Howell
890 Dooley, Mr. Patrick
Name: Name, Length: 517, dtype: object
列に対して文字列部分一致検索での件数出力
リストに検索語句を個々に入れて、各検索語句でヒットした件数を出力します。
# 文字列部分一致で件数カウント
titles = ["Mr.", "Miss.", "Mrs.", "Master.", "Dr.", "Rev.", "Col.", "Ms.",
"Mlle.", "Mme.", "Capt.", "Countess.", "Major.", "Jonkheer.", "Don.",
"Dona.", "Sir.", "Lady."]
total = 0
for i, title in enumerate(titles):
print(i, title, ": ", train_data.Name.str.contains(title, regex=False).sum())
total += train_data.Name.str.contains(title, regex=False).sum()
print("Total: ", total)
0 Mr. : 517
1 Miss. : 182
2 Mrs. : 125
3 Master. : 40
4 Dr. : 7
5 Rev. : 6
6 Col. : 2
7 Ms. : 1
8 Mlle. : 2
9 Mme. : 1
10 Capt. : 1
11 Countess. : 1
12 Major. : 2
13 Jonkheer. : 1
14 Don. : 1
15 Dona. : 0
16 Sir. : 1
17 Lady. : 1
Total: 891
列に対して文字列部分一致検索した結果を新しい列に追加
文字列検索した結果、合致した文字列をTitle
という列に追加しています。
# 'Name'に'Titleリストの文字を含んでいた場合は列'Title'に設定
for title in titles:
train_data.loc[train_data.Name.str.contains(title, regex=False), 'Title'] = title
print(train_data.loc[:,['Name', 'Title']])
Name Title
0 Braund, Mr. Owen Harris Mr.
1 Cumings, Mrs. John Bradley (Florence Briggs Th... Mrs.
2 Heikkinen, Miss. Laina Miss.
3 Futrelle, Mrs. Jacques Heath (Lily May Peel) Mrs.
4 Allen, Mr. William Henry Mr.
.. ... ...
886 Montvila, Rev. Juozas Rev.
887 Graham, Miss. Margaret Edith Miss.
888 Johnston, Miss. Catherine Helen "Carrie" Miss.
889 Behr, Mr. Karl Howell Mr.
890 Dooley, Mr. Patrick Mr.
可視化
相関行列
corr
関数を使って相関行列を出力します。無駄な行を省くために列名を指定しています。留意点です。
- データ型がobject(文字列)は除外され、数値(int, float)型およびbool型(Trueが1、Falseが0)の相関係数が算出されます。
- 相関係数算出方法のデフォルトはピアソンの積率相関係数
- 欠損値NaNは計算から除外
-
matplotlib
でグラフ化しているわけではない -
style
とbackground_gradient
を使ってヒートマップっぽく表示することで見やすい
※参考記事「【1行で】Pandasだけで相関行列をヒートマップっぽく可視化する」
train_data.loc[:,
["Survived", "Pclass", "Age", "SibSp", "Parch", "Fare"]].corr().style.background_gradient(axis=None)
グラフ
少量データはExcelでグラフ作ったりしたほうが早いのですが、慣れのためにライブラリmatplotlib
でグラフ出力やってみます。
DataFrameの列を簡単に出力するだけなら1行で出来ます。この辺はPandasの素晴らしい点ですね。
train_data.Survived.value_counts(sort=False).plot.bar()
欠損値をグラフがどのように解釈するかは注意が必要です。
matplotlibの基本
簡易的な出力なら上記のコードだけでいいのですが、グリッドやラベル、グラフを並べるなど、いろいろしたくなります。そのときに基本を知っておく必要があります。
今まで、適当にググりながらグラフ表示してきた人は、記事「早く知っておきたかったmatplotlibの基礎知識、あるいは見た目の調整が捗るArtistの話」を読みましょう。2種類の流儀が世の中に混同されていますが、そこを整理してくれます。
あと、有名な日本語使用に関する豆腐問題は「豆腐(グラフ文字化け対応)対応」を参照ください。
細かい調整をしようと思ったら記事「matplotlibのめっちゃまとめ」が参考になります。
グラフの並列表示
ダッシュボードのようにグラフを並べて表示したくなることがあります。その場合はplt.subplots
時に行数(nrows)・列数(ncols)と全体のサイズを指定します。ここで取得したaxes
で個々のグラフに関する調整をします。
まずは、おまじないのように以下のコマンドを実行。
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=2, ncols=3, figsize=(12, 3))
ここで、エリア全体を司るfig
を使えば、例えばグラフエリア間の余白長さを調整できます。私の乏しい経験ではあまり使いません。例えば、余白を調整してみます(わかりやすいようにあえて大きくしています)。
fig.subplots_adjust(wspace=3, hspace=3)
axesは配列です。個々のグラフを司ります。例えばX軸ラベルをset_xticklabels
で変えてみます(グラフ左下)。print(axes.shape)
の出力は(2, 3)
です(plt.subplots
で指定した行列数)。
fig, axes = plt.subplots(nrows=2, ncols=3, figsize=(12, 3))
print(axes.shape)
axes[1, 0].set_xticklabels(labels=['aaa', 'bbb'], rotation=30, horizontalalignment="center")
より柔軟な配置をする場合は以下のページが参考になります。
基本: 円グラフ
割合を見たい場合には円グラフですね。autopct="%1.1f%%
とすることでデータラベルを%で小数点第1位まで出してくれます。value_counts
時にソートをOFFにしているのは、ラベルとの整合性を保つためです(自動でラベル出力されるのですが、「0」と「1」だと意味がすぐにわからない
ので追加)。
位置 | オプション |
---|---|
左 | オプションなし |
中央 | ラベルあり |
右 | ラベル、割合データラベル(autpct)あり |
fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(12, 3))
fig.subplots_adjust(wspace=0.5, hspace=0.5)
labels_survived = ["0: Dead","1: Survived"]
train_data.Survived.value_counts(sort=False).plot.pie(ax=axes[0])
train_data.Survived.value_counts(sort=False).plot.pie(labels=labels_survived, ax=axes[1])
train_data.Survived.value_counts(sort=False).plot.pie(labels=labels_survived, autopct="%1.1f%%", ax=axes[2])
plt.show()
基本: 棒グラフ(積上でない)
棒グラフにset_xticklabels
でラベルを追加し、向きを傾けています。また、grid
でY軸にグリッドを追加します。同じグラフの3つを並列で比較しています。
value_counts
時にソートをOFFにしているのは、ラベルとの整合性を保つためです。
4列目のデータラベルを出力するコードは少しトリッキーです。text
関数を使ってX座標とY座標を指定して主力しています(少し見にくい)。
位置 | オプション |
---|---|
1列目 | オプションなし |
2列目 | ラベルあり |
3列目 | ラベルあり、ラベル向き調整 |
4列目 | ラベルあり、ラベル向き調整、データラベルあり |
LABELS_SURVIVED = ['0: Dead', '1: Survived']
sr_survived = train_data.Survived.value_counts(sort=False)
fig, axes = plt.subplots(nrows=1, ncols=4, figsize=(16, 3))
fig.subplots_adjust(wspace=0.5, hspace=0.5)
sr_survived.plot.bar(ax=axes[0])
sr_survived.plot.bar(ax=axes[1])
sr_survived.plot.bar(ax=axes[2])
sr_survived.plot.bar(ax=axes[3])
axes[1].set_xticklabels(labels=LABELS_SURVIVED)
axes[1].grid(axis='y', linestyle='dotted')
axes[2].set_xticklabels(labels=LABELS_SURVIVED, rotation=30, horizontalalignment='center')
axes[2].grid(axis='y', linestyle='dotted')
axes[3].set_xticklabels(labels=LABELS_SURVIVED, rotation=30, horizontalalignment='center')
axes[3].grid(axis='y', linestyle='dotted')
# 2つのcountは順にy軸の座標と出力テキスト
[axes[3].text(i, count, count, horizontalalignment='center', color='green')
for i, count in enumerate(sr_survived)]
plt.show()
基本: 棒グラフ(2種類データを積上含めて出力)
2種類のデータがあるので、ax.legend
で凡例出力してわかりやすくします。
位置 | オプション |
---|---|
1行目1列目 | 積上なしでデータ横並び |
1行目2列目 | 積上なしでデータ横並びにしてデータラベル追加 |
2行目1列目 | 積上(stackedをTrue) |
2行目2列目 | 積上(stackedをTrue)にしてデータラベル追加 |
2行目3列目 | 積上を100%表示(value_counts時にnormalizeをon) |
def arrange_bar(ax, x_labels, y_labels=[]):
ax.set_xticklabels(labels=x_labels, rotation=30, horizontalalignment="center")
hans, labs = ax.get_legend_handles_labels()
ax.legend(handles=hans, labels=y_labels)
ax.grid(axis='y', linestyle='dotted')
LABELS_SURVIVED = ['0: Dead', '1: Survived']
LABELS_PCLASS = ["1: 1st(Upper)", "2: 2nd(Middle)", "3: 3rd(Lower)"]
df_pclass = train_data.groupby(["Pclass"])["Survived"].value_counts(sort=False).unstack()
fig, axes = plt.subplots(nrows=1, ncols=4, figsize=(16, 3))
fig.subplots_adjust(wspace=0.5, hspace=0.5)
df_pclass.plot.bar(ax=axes[0])
df_pclass.plot.bar(ax=axes[1], stacked=True)
df_pclass.plot.bar(ax=axes[2], stacked=True)
train_data.groupby(["Pclass"])["Survived"].value_counts(sort=False, normalize=True).unstack().plot.bar(ax=axes[3], stacked=True)
arrange_bar(axes[0], LABELS_PCLASS, LABELS_SURVIVED)
arrange_bar(axes[1], LABELS_PCLASS, LABELS_SURVIVED)
arrange_bar(axes[2], LABELS_PCLASS, LABELS_SURVIVED)
[axes[2].text(i, item.sum(), item.sum(), horizontalalignment='center', color='green')
for i, (_, item) in enumerate(df_pclass.iterrows())]
arrange_bar(axes[3], LABELS_PCLASS, LABELS_SURVIVED)
plt.show()
実践
基本をもっと書こうかとも思ったのですが、時間ないので今は書きません(いつ書くかわからない)。実際にKaggle Titanic Challengeしたときのグラフ出力系コードです。
グラフ上に数値ではなくラベルを出したいので、以下のように辞書でラベルを定義。
# 今後も使うラベル
DICT_SURVIVED = {0: '0: Dead', 1: '1: Survived'}
DICT_PCLASS = {1: '1: 1st(Upper)', 2: '2: 2nd(Middle)', 3: '3: 3rd(Lower)'}
DICT_EMBARK = {'C': 'Cherbourg', 'Q': 'Queenstown', 'S': 'Southampton'}
円グラフと棒グラフの並列
生死をの数を単純に見たいときに円グラフと棒グラフを並べました。arrange_bar
はこの後でも使います。
タイタニック号の事件のことなどまるで知りませんでしたが、思ったより助かっているのですね。
# 棒グラフのX軸ラベルを回転させ、Y軸にグリッド追加
def arrange_bar(ax):
ax.set_xticklabels(labels=ax.get_xticklabels(),
rotation=30, # xラベルを回転(完全に縦だと見にくい)
horizontalalignment="center")
ax.grid(axis='y', linestyle='dotted') # Y軸グリッド追加
# 生死の数をカウントし、グラフでわかりやすいように名称変更
sr_survived = train_data['Survived'].value_counts().rename(DICT_SURVIVED)
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(8, 3))
fig.subplots_adjust(wspace=0.5, hspace=0.5)
sr_survived.plot.pie(autopct="%1.1f%%", ax=axes[0]) # 円グラフ
sr_survived.plot.bar(ax=axes[1]) # 棒グラフ
arrange_bar(axes[1])
[axes[1].text(i, count, count, horizontalalignment='center')
for i, count in enumerate(sr_survived)] # データラベル追加(x座標i, y座標countにcountを表示)
plt.show()
円グラフ・積上棒グラフ・積上でない棒グラフ・100%棒グラフ
円グラフ・積上棒グラフ・積上でない棒グラフ・100%棒グラフを並べます。
まずはコードから。積み上げでない棒グラフにデータラベルを出力する部分がトリッキーです。また、凡例がすでにテキストでわかりやすいやつはいいのですが、数字で「なんだっけ?」というやつは辞書で変換して出力しています。
def output_bars(column, index={}):
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(12, 8))
fig.subplots_adjust(wspace=0.5, hspace=0.5)
# 列の Value Count
sr_vc = train_data[column].value_counts()
# 列ごとの生死 Value Count
df_vc = train_data.groupby([column])['Survived'].value_counts(sort=False).unstack()
# 列ごとの生死 Value Count(標準化あり)
df_vc_norm = train_data.groupby([column])['Survived'].value_counts(
sort=False, normalize=True).unstack()
# index(リネームする凡例)がない場合
if len(index) == 0:
df_vc.rename(columns=DICT_SURVIVED, inplace=True)
df_vc_norm.rename(columns=DICT_SURVIVED, inplace=True)
# index(リネームする凡例)がある場合
else:
sr_vc.rename(index, inplace=True)
df_vc.rename(index=index, columns=DICT_SURVIVED, inplace=True)
df_vc_norm.rename(index=index, columns=DICT_SURVIVED, inplace=True)
sr_vc.plot.pie(ax=axes[0, 0], autopct="%1.1f%%") # 円グラフ
df_vc.plot.bar(ax=axes[0, 1], stacked=True) # 積上棒グラフ
df_vc.plot.bar(ax=axes[1, 0]) # 棒グラフ
df_vc_norm.plot.bar(ax=axes[1, 1], stacked=True) # 100%棒グラフ
arrange_bar(axes[0, 1])
arrange_bar(axes[1, 0])
arrange_bar(axes[1, 1])
# 積上棒グラフにデータラベル追加
[axes[0, 1].text(i, item.sum(), item.sum(), horizontalalignment='center')
for i, (_, item) in enumerate(df_vc.iterrows())]
# 棒グラフにデータラベル追加
for rect in axes[1, 0].patches:
height = rect.get_height()
axes[1, 0].annotate('{:.0f}'.format(height),
xy=(rect.get_x() + rect.get_width() / 2, height),
xytext=(0, 3), # 3 points vertical offset
textcoords="offset points",
ha='center', va='bottom')
plt.show()
PClass(チケットクラス)
先程定義した関数output_bars
を呼び出します。カテゴリ変数1, 2, 3だとわかりにくいので、辞書も渡します。
3(Lower)の安いチケットだと死にやすいのが一目瞭然ですね。
output_bars('Pclass', DICT_PCLASS)
Sex(性別)
今度は、テキストが入っている列「Sex」なのでラベル辞書は渡していません。
女性は8割弱助かっているのが興味深いです。レディファーストの精神で、救命ボートに先に乗せていったのでしょうか。
output_bars('Sex')
Embarked(出港地)
タイタニック号に乗った港です。乗った港によってなぜ生死の確率が左右するのかまるで理解できないです。
output_bars('Embarked', DICT_EMBARK)
箱ひげ図とヒストグラムの並列
数値系項目で分布をみたいときに箱ひげ図とヒストグラムで可視化しました。
ヒストグラムは、3行目に範囲を絞って見られるようにもしています。
# グラフで欠損値は自動除去されている
def output_box_hist(column, bins=20, query=None):
# 3行目に範囲を絞ってヒスとグラムを出さない場合
if query == None:
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(12, 8))
# 3行目に範囲を絞ってヒスとグラムを出す場合
else:
fig, axes = plt.subplots(nrows=3, ncols=2, figsize=(12, 12))
train_data.query(query)[column].hist(ax=axes[2, 0], bins=bins) # 範囲限定ヒストグラム
train_data.query(query).groupby('Survived')[column].plot.hist(
ax=axes[2, 1], bins=bins, alpha=0.5, legend=True, grid=True) # 範囲限定ヒストグラム(生死別)
axes[2, 1].legend(labels=[DICT_SURVIVED[int(float((text.get_text())))]
for text in axes[2, 1].get_legend().get_texts()]) # 凡例表示
fig.subplots_adjust(wspace=0.5, hspace=0.5)
train_data.boxplot(ax=axes[0, 0], column=[column]) # 箱ひげ図
train_data.boxplot(ax=axes[0, 1], column=[column], by='Survived') # 箱ひげ図(生死別)
axes[0, 1].set_xticklabels([DICT_SURVIVED[int(float(xticklabel.get_text()))]
for xticklabel in axes[0, 1].get_xticklabels()]) # x軸にラベル表示
train_data[column].hist(ax=axes[1, 0], bins=bins) # ヒストグラム
train_data.groupby('Survived')[column].plot.hist(
ax=axes[1, 1], bins=bins, alpha=0.5, grid=True, legend=True) #ヒストグラム
axes[1, 1].legend(labels=[DICT_SURVIVED[int(float((text.get_text())))]
for text in axes[1, 1].get_legend().get_texts()]) # ヒストグラム(生死別)
plt.show()
Age(年齢)
年齢平均値は生死によって関係なさそうですが、15才以下だと生存確率が高いです。これも、女性は生存確率が高いのと同様、子供を優先的に助けたのでしょうか。
output_box_hist('Age')
Fare(運賃)
データが200以下に集中していたので、3行目に200以下のデータを出力しました。
安い料金を払っている人は死ぬ確率が非常に高いですね。貧乏人は粗末に扱われた、のでしょうか。
output_box_hist('Fare', 20, 'Fare < 200')
左右縦棒グラフとテーブル
種類が多いと横棒グラフはラベル出力の関係上、見にくくなります。そのため、縦棒グラフを出しました。
前処理
Titanicのファイル読み込みしたデータを加工します。この記事の本題と異なるのでスキップしてもらえれば。
上の方で書きましたが、名前からタイトル(Mrなど)を抜き出し、新しい列に設定します。その後に、タイトルごとに人数と死亡率のDataFrameを作ります。
# 'Name'に'Titleリストの文字を含んでいた場合は列'Title'に設定
for title in titles:
train_data.loc[train_data.Name.str.contains(title, regex=False), 'Title'] = title
# Title出力用dfを作成し、トータルと死亡率計算
train_title = train_data.groupby(['Title'])['Survived'].value_counts().unstack().rename(columns=DICT_SURVIVED)
train_title = pd.concat([train_title, pd.DataFrame(train_title.sum(axis=1), columns=['Total'])], axis=1)
train_title['Death Rate'] = round(train_title['0: Dead'] / train_title['Total'], 2)
print(train_title)
タイトルごとの死亡率表示
縦棒グラフを左右にして表示。一番右の列にテーブルを表示します。1行目は総数で降順ソート、2行目は死亡率で降順ソート。
2行目のテーブルはソート順がグラフと完全に一致していません。「Death Rate」が同じ値だとうまくソート順がうまくいかず、何か方法があるのでしょうが、調べていません。
1行目の「Master」より下は数が少なすぎて、あまり機械学習に使えなそうです。「Master」は「少年ないし青年男性」の
ことのようです(スターウォーズのヨダみたいなイメージかと思っていたら違いました)。若年層は男性であってもそこそこ生存確率高いということですね。
def arrange_barh(ax, title):
ax.set_ylabel('')
ax.grid(axis='x', linestyle='dotted')
ax.set_title(title)
def show_two_barh(axes, field, df):
df.plot.barh(ax=axes[0], stacked=True, y=[0, 1])
df['Death Rate'].plot.barh(ax=axes[1], color='green')
axes[0].invert_xaxis()
axes[0].set_yticklabels([])
arrange_barh(axes[0], 'Total')
arrange_barh(axes[1], 'Death Rate')
axes[2].axis('tight')
axes[2].axis('off')
df.sort_values(field, ascending=False, inplace=True)
axes[2].table(cellText=df.values,
colLabels=df.columns,
rowLabels=df.index, loc='center')
def output_barh(df, height):
fig, axes = plt.subplots(nrows=2, ncols=3, figsize=(18, height))
fig.subplots_adjust(wspace=0.3, hspace=0.2)
show_two_barh(axes[0], 'Total', df.sort_values('Total')) # 1行目はTotalでソート
show_two_barh(axes[1], 'Death Rate', df.sort_values('Death Rate', na_position='first')) #2行目は死亡率でソート
plt.show()
ある項目ごとのヒストグラム
タイトルごとの年齢ヒストグラムです。日本人に馴染みにくいタイトルの理解一助になりそうです。
_, ax = plt.subplots(figsize=(16, 15))
train_data.Age.hist(ax=ax, by=train_data['Title'])
plt.show()