この記事はNuco Advent Calendar 2023の21日目の記事です。
第1章:はじめに
本記事の目的
さてさて、この記事を読んだらいったい何が出来るようになるのよ!っていうのが、気になるところではあると思います。簡単に対象レベルを述べるのであれば、以下のような人が挙がってくるのではないでしょうか?
<対象レベル>
・何となくPythonを勉強し始めてみたけど、何やってみようかな?と考え中の方
・データ分析をこれからやってみたいなって思っている方
・就活もしくは転職でデータサイエンティスト、データアナリストを目指している方
・普段SQLは使っているけど、Pandasだとどうやるんだ?となっている方
などなど、様々な境遇の皆さんに刺さる記事になってくれれば。。!
<出来るようになること>
・グラフ出力に必要なデータの加工
・よく使う一般的なグラフの出力
・各グラフの持つ特徴の理解
最後の『特徴』って何だよって感じですが、実務では出力をしたグラフの体感半分くらいの行先は他者の目に止まる資料などです。彼らが例えあなたの出力したグラフの背景知識に乏しかったとしても、「あぁなるほどね!理解理解!」と言わせなければなりません。であれば、どのグラフを使用するか決定するのに『グラフの持つ特性』を理解することは必要不可欠です!
ではでは、最後までお付き合いよろしくお願いしますm(__)m
弊社Nucoでは、他にも様々なお役立ち記事を公開しています。よかったら、Organizationのページも覗いてみてください。
また、Nucoでは一緒に働く仲間も募集しています!興味をお持ちいただける方は、こちらまで。
タイタニックデータについて
1.タイタニック号沈没事件
それでは早速ですが皆様、こちらの船はご存知でしょうか?
https://voi.id/ja/memory/273057 『1912年4月15日:大西洋に沈没したタイタニック号』
はい、かの有名なタイタニック号ですね!
まあ歴史事実としても有名ですし、映画化もされていますよね。
いや観たことないよ!って人でも主題歌『My Heart Will Go On』を聴けば、
あぁこれタイニックなんだ!!ってなるでしょう。
多くの犠牲者を出してしまったタイタニック号事件ですが、Kaggleという機械学習のコンペサイトには、乗客情報とその乗客の生死が記録されているデータがあります。
本記事では、そのデータを用いて解説をしていこうと思います。
2.タイタニックデータをダウンロードしよう
Step 1: Kaggleにアクセス
Step 2: 右上のRegiterをクリック
Step 3: Googleアカウント、もしくはメールアドレスで登録
Step 4: トップページ検索欄から『Titanic - Machine Learning from Disaster』と検索
Step 5: 検索結果から『Titanic - Machine Learning from Disaster』を選択
Step 6:『Data』を選択
Step 7: 下にスクロールして、右下の『Summary』からダウンロード
3.タイタニックデータを見てみよう
では、早速タイタニックデータをダウンロードして、中身を見てみましょう。
データの取り込みと出力は以下のように実行します。
import pandas as pd
# CSVファイルの読み込み
df = pd.read_csv('train.csv')
# trainデータを出力
df
カラム名 | 説明 |
---|---|
PassengerId | 乗客の一意の識別番号 |
Survived | 乗客が生存したかどうか(1: 生存, 0: 死亡) |
Pclass | 乗客の社会経済的地位を示すクラス(1st, 2nd, 3rd) |
Name | 乗客の名前 |
Sex | 乗客の性別 |
Age | 乗客の年齢 |
SibSp | タイタニック号に同乗している兄弟または配偶者の数 |
Parch | タイタニック号に同乗している親または子供の数 |
Ticket | チケット番号 |
Fare | 乗船料金 |
Cabin | 部屋番号 |
Embarked | 乗船した港(C: Cherbourg, Q: Queenstown, S: Southampton) |
いかがでしょうか?
このような生々しいデータに触れるなんて凄い時代ですよね😭
それでは、次の章からこのデータをつかってPandasの基本操作を確認していきます!!
第2章:データ操作ためのPandas基礎知識
そもそもPandasって何?
PandasはPythonでモデリングする際のいわゆる前処理段階で力を発揮するライブラリーです。様々なデータ加工処理をスムーズに行うことができ、表計算やデータの抽出・検索などを行うことができます。例えば、読み込んだデータからある条件を満たすindex(行)を抽出したり、あるカラム(列)の平均値などの統計量を算出、さらにはデータ同士の結合などの操作を行うことができます。データベースのSQLや、より一般的なものだとExcelとほぼ同じような役割を果たしてくれます。
Pandasの入力形式・出力形式
CSVが一般的ですが、他の形式も多く対応していますので以下の表にまとめておきます。
データ形式 | 入力メソッド | 出力メソッド |
---|---|---|
CSV | read_csv |
to_csv |
Excel | read_excel |
to_excel |
JSON | read_json |
to_json |
HTML | read_html |
to_html |
SQL | read_sql |
to_sql |
Parquet | read_parquet |
- |
Feather | read_feather |
- |
Clipboard | read_clipboard |
to_clipboard |
HDF5 | read_hdf |
to_hdf |
Msgpack | read_msgpack |
to_msgpack |
Stata | read_stata |
to_stata |
SAS | read_sas |
- |
Pickle | read_pickle |
to_pickle |
データの基本情報を調べる
1.先頭・末尾の5行を抽出
まずは簡単にデータの中身を見たい時に役立つメソッドのご紹介から、、、
先頭5行の表示
df.head()
先頭N行の表示
df.head(N)
末尾5行の表示
df.tail()
()
内に何も入れなければ、デフォルトの5行が表示されます。
頭のhead,尻尾のtailなので覚えやすいですよね☺️
では、試しに実行して出力結果を見てみましょう。
#先頭5行を出力
df.head()
#末尾5行を出力
df.tail()
想像通りの結果ですね。
ちなみにindex(行番号)は0始まりなので、一緒に覚えておきましょう!
2.データフレームの大きさ
『データフレームの大きさ』と言われても、
まずデータフレームってなんだよ!!って最初はなりますよね。
今回で言えば、読み込んでいまdf
に入っている”表”のことですから、
つまりは何行何列の表かを知りたいわけです。
そんな時は以下のように書けばOKです!
#データフレームの大きさの確認
df.shape
#データフレームの大きさを確認
df.shape
そうすると出力は、
となります。
この出力結果は行・列の順番に記載されています。
覚え方は『行列』でもいいですし、(x,y)と数学で記載するように
(x方向、y方向)つまり(行数、列数)でも良いんじゃないでしょうか?
3.基本統計量の表示
次に、読み込んだデータの統計量を簡単に確認する方法を紹介します。
ちなみに統計量とは、平均や最大値などのデータから計算できる値のことを言います。
基本統計量の表示
df.describe()
英語でdescribeは『〜を説明する。〜を描写する。』という意味ですので、覚えやすいですね!
では出力させてみましょうかね。
#基本統計量の表示
df.describe()
簡単に表示された統計量についてまとめておきます。
カラム名 | 説明 |
---|---|
count | 件数 |
mean | 平均(算術平均) |
std | 標準偏差 |
min | 最小値 |
25% | 第1四分位数 |
50% | 中央値(第2四分位数) |
75% | 第3四分位数 |
max | 最大値 |
数Ⅰまでに習ったものばかりですね。(今は中3で中央値をやってるらしい。。)
中央値は後程述べますので、第1四分位数・第3四分位数に関して少しだけ復習を、、、
第1四分位数:最小値と中央値(第2四分位数)の”中央値”
第3四分位数:中央値(第2四分位数)と最大値の”中央値”
でしたね?
こんな感じで、describe()
を使うことで、
数行眺めただけでは得られない情報が一瞬で確認できるので、是非とも覚えておきましょう🥸
データの選択とフィルタリング
1.列や行の選択
カラムを選択したい時は、
df[['欲しいカラム名1', '欲しいカラム名2',...]]
とするだけです!
このように、DataFrame 型のオブジェクトに対して、[]
でインデックスを指定することで対象カラムのデータのみ抽出可能です。このとき、インデックスを対象カラム名のリスト ["カラム名1", "カラム名2", ...]
で与えなければならないことに注意しましょう。
それでは、早速乗客の名前と生存情報を抽出してみましょう!
#NameとSurvivedのみ抽出
df[['Name', 'Survived']]
簡単ですよね!!
df[['Name', 'Survived']]
からNameとSurvivedのみしか出力されていませんね。
ちなみに3つ以上のカラムを出力したいときは、以下のようにリスト内に加えていけばOKです!
#Name,Sex,Survivedのみ抽出
df[['Name', 'Sex', 'Survived']]
2. 条件に基づくフィルタリング
条件を課したい時は、以下のように記述します。
df [df['条件を課すカラム名'] == num]
(等号成立)
df[df['条件を課すカラム名'] >= num]
(以上)
df[df['条件を課すカラム名'] < num]
(未満)
Pythonを少し触ったことがある人なら分かるかもしれませんが、
条件式なのでif文と同様、=を2つ付けるんですね〜
では、生存した乗客のデータのみピックアップしてみましょう。
言い換えれば、Survivedが1となる列のみ出力すればいいわけです!
# Survivedが1の行だけを抽出
df[df['Survived'] == 1]
ご覧のとおり、Survivedの列は1しか無くなってしまいましたね👍
少し補足します。
df['条件を課すカラム名'] == num
の部分だけを実行したらどうなるんでしょうか?
df['Survived'] == 1
はい。条件式が成立したインデックス(行番号)がTrue, 不成立がFalseで表記されていますね!
つまり、前項と同様に[]
でTrueとなるインデックスを指定しているわけです。
3.複数条件の組み合わせ
次は複数の条件を課してみましょう。
条件式を複数使用する場合は、以下のように論理演算子を用います‼️
df[(条件式1) 論理演算子 (条件式2)]
論理演算子 | 意味 |
---|---|
& | 積集合(かつ条件) |
| | 和集合(または条件) |
^ | 排他的論理和(一方が真、他方が偽のもの) |
3つ目を除けば、「あ!これね!」って感じですよね!主に上2つがメインです。
自分の今やりたいことは、どの演算子でいけるかな?と考えてみて下さいね(^-^)
では例えば、
『Queenstownから乗船した女性』という条件は『EmbarkedがQ,かつSexがfemale』と言い換えできますね!
なので、
# 生存した女性のデータを抽出
df[(df['Embarked'] == 'Q') & (df['Sex'] == 'female')]
というわけですね!
今回はかつ条件(積集合)なので&でしたが、
または条件(和集合)であれば | に置き換えればオッケーです⭕️
どうですか?少しずつ幹らしきモノが見えてきましたか?
これまでと同様にどうやってインデックスを指定するかですよね!
4.行・列の削除
さて、次は行・列の削除について扱います。
上でやったように、カラムの要素に条件を与えることで『削除』と同義になりますが、
今回はdrop
メソッドを使ってやってみましょう☝️
使い方は以下の通り!
<行の削除>
df.drop(["削除したい行のindex番号1", "削除したい行のindex番号2",・・・], axis=0)
⇨index指定の場合はリスト型[]
に!
<列の削除>
①消したいカラム(列)が1つの場合
df.drop("削除したい列のカラム名1", axis=1)
②消したいカラム(列)が複数の場合
df.drop(["削除したい列のカラム名1", "削除したい列のカラム名2",・・・], axis=1)
dropメソッドですので、drop[]
としないように注意⚠️
列の削除の場合でも、複数カラムの場合はリスト型[]
で指定しないといけないので注意⚠
上記のことに注意して、まずは先頭の5行を消してみましょう。
#リストは0番スタートなので先頭5個は0〜4
df.drop([0, 1, 2, 3, 4], axis=0)
次に列(カラム)を複数削除してみましょうか。
まあ何でもいいんですが、
個人情報になり得そうな名前、性別、年齢、チケット番号を消しましょう。
(本当に何でもいいですよ)
#Name,Sex,Age,Ticketを削除
df.drop(["Name", "Sex", "Age", "Ticket"], axis=1)
メソッドを使うとより直感的に理解できるのではないでしょうか?
欠損値の取扱い
1.欠損値の検出
先から出力されたデータフレームを見ていると、NaNが目に入ってきません?
これが欠損値と呼ばれものです。まあ、情報がないってことですよ!
(発生原因は、入力忘れや無回答、システム上の問題など様々)
まずは、各カラムに欠損値がどれだけあるかを確認してみましょう!
#欠損値の検出
missing_values_per_column = df_data.isnull().sum()
#欠損値のあるカラムを出力
missing_values_per_column
言うまでもありませんが、一応まとめときましょうか。。
年齢(Age)不明が177人
部屋番号(Cabin)不明が687人
乗船した港(Embarked)不明が2人
こんな感じです。
2.欠損値の補完と削除
欠損値を把握したら、今度は補完(妥当と思われる値を入れること)してみましょう!
今回は年齢(Age)を平均値で補完してみようと思います!
# 年齢の平均値を計算
average_age = df_data['Age'].mean()
# 年齢の欠損値を平均値で補完
df_data['Age'] = df_data['Age'].fillna(average_age)
#欠損値の検出
missing_values_per_column = df_data.isnull().sum()
#欠損値のあるカラムを出力
missing_values_per_column
先程まで177個も欠損値があったAgeが0個になっていますね!
コードの説明ですが、
.mean()
で平均値の計算
.fillna()
で欠損値の補完をしているわけです!
3.欠損値の統計情報
少々ここで脱線します。(一回休憩☕️)
機械学習を学び始めたばかりだと私を含め、
『欠損値はない方がいい!!埋めなければ!!!!』なんて思ったりもします😅
しかし必ずしもそうではありません!
例えば、
・ユーザーがある意図を持ってアンケートで空欄にした
・駐車場の有無を1,0で表していたが、nullはデータの入手不可を意味していた
つまり、
欠損値であることが有効な情報になることもあるのです!
だからこそいきなり欠損値補完するのではなく、一回思考を踏む必要があるわけですね。
無視するのがいいか、除外するのがいい、それらしい値を入れるのか、これが重要です。
取る方法によっては、大きなバイアスのある結果を与え、誤った意思決定に繋がってしまい、大きな損失を被る可能性があります。
ですから、より慎重に。。。
って、私も尊敬する先輩から教わりました笑笑
データの集約
さてさて、ここではよく使う集約メソッド4つ紹介します。
カラム名 | 説明 |
---|---|
count() |
件数 |
sum() |
合計 |
mean() |
平均(算術平均) |
median() |
中央値(第2四分位数) |
max() |
最大値 |
min() |
最小値 |
corr() |
相関係数 |
では実際に使っていきましょう!!
1.件数(count)
countメソッドを使って、生存者者数・非生存者数を出してみましょう。
# 生存者と非生存者の人数を計算
survived_count = df_data[df_data['Survived'] == 1]['PassengerId'].count()
not_survived_count = df_data[df_data['Survived'] == 0]['PassengerId'].count()
# 結果を表示
print("生存者の人数:", survived_count)
print("非生存者の人数:", not_survived_count)
2.合計(sum)
『欠損値の補完(欠損値の検出)』のとこでしれっと登場していましたが、
もう一度確認しときます!
今回はFare(料金)の合計値でも出してみます。
# Fare列の値の合計を計算
total_fare = df['Fare'].sum()
print(f'Total Fare: {total_fare}')
最近の為替で円に直せば大体400万程度といったところでしょうか。
やはり、物価は当時に比べたら遥かに上がっていますね〜
3.平均(mean)
はい!!!
一個前の節では年齢の平均を扱いましたので、今回はチケット代を平均してみましょう。
# Fareの平均を計算
average_fare = df_data['Fare'].mean()
# Fareの平均を小数点第一位まで丸める
average_fare = round(average_fare,1)
# 結果を表示
print("Fareの平均:", average_fare)
ちょっと知識の補充がてらroundメソッドを使用してみました😎
使い方は小数第N位に丸めたいとするなら、round(丸めたい数字,N)
とすればいいです!
4.中央値(median)
平均値の次は中央値です。
何となく似たような値かな?なんて高校生の頃は思ったりもしましたが、実はちがう。。。
# Fareの中央値を計算
median_fare = df_data['Fare'].median()
# Fareの中央値を小数点第一位まで丸める
median_fare = round(median_fare,1)
# 結果を表示
print("Fareの中央値:", median_fare)
平均値と中央値でどちらを選ぶべきかという話を少しだけしましょう。
結論、外れ値の影響を受けやすいかどうかです!
「5人が物理のテストを受けた結果、
4人が10点以下を取ったが1人だけ100点だった。」
これで平均値が機能しないのは何となく想像できますよね?
え!?じゃあ少し実験してみましょう。
『A:100点 B:5点 Cさん:2点 Dさん:8点 Eさん:10点』
だったとします。この状況で平均値と中央値それぞれ求めると、
平均値:25点 中央値:8点
さあ、普通の人がこのテスト受けた時に取りそうな点数はどちらの値ですか?
中央値の方ですよね!
このように上のような事象では中央値の方が、私たちの持つ『平均』のイメージとなるのです。
以下のように覚えておいて下さいね!
中央値は平均値に比べ、外れ値の影響を受けいにくい
5.最大値・最小値(max・min)
では次に乗客の最年長、最年少を求めてみましょう。
# Ageの最大値と最小値を計算
max_age = df_data['Age'].max()
min_age = df_data['Age'].min()
# 結果を表示
print("Ageの最大値:", max_age)
print("Ageの最小値:", min_age)
なんか不思議な値が出てきましたね😅
おそらく、生後5ヶ月という意味なのでしょう。
6.相関係数(corr)
では集約メソッドの締めくくりに年齢(Age)と料金(Fare)の相関係数を算出しましょう。
相関係数は-1から1の値を取り、1に近いほど正の相関,-1に近いほど負の相関が強いと言えます。
よく使う指標ですので、思い出しておくと良いでしょう。
# Age列とFare列の相関係数を計算
correlation = df[['Age', 'Fare']].corr()
print(correlation)
表の見方ですが、行名と列名が異なる値がその二つの相関係数です。
今回はAgeとFareの相関係数が0.096067ですので一応正の相関ですね?
私は年配の乗船客の方が高めの運賃を払っているかと予想していましたが、
あながちそうとも言い切れない微妙な結果でした・・・😭
その他の実用的なメソッド
Pandasの文法紹介の締めくくりは、これまでで紹介できなかったデータ操作について扱います。この章もあと少しです。頑張りましょう!
1.並びかえ(ソート)
「ソート」とは、データをある基準に基づいて順番に並べ替えることを指します。これにより、データが整理され、特定のパターンや傾向を見つけやすくなります。
①要素を並べたいカラムが1つ
df.sort_values(by='要素を並べ替えたいカラム', ascending=True)
②要素を並べ替えたいカラムが複数
df.sort_values(by=['要素を並べ替えたいカラム1', '要素を並べ替えたいカラム2',・・・], ascending=True)
・昇順(1, 10, 100, 1000)の場合
ascending=True
・降順(1000, 100, 10, 1)の場合
ascending=False
複数のカラムについて並べ替える際、リスト内に記述したカラム順が優先順位となる。
drop
メソッドのときと同様に、列の場合も複数選択の場合はlistで入れることを忘れないでください!
では、今回は年齢と料金の昇順ソートを行ってみましょう。
#Age列とFare列で昇順ソート(Age優先)
df.sort_values(by=['Age', 'Fare'], ascending=True)
indexが644,831のところを見てみましょう。
ここでは、Ageの昇順が優先されているので、Fareの大小が逆転していますよね?
このように複数カラムでソートする場合は、リスト内に記載する順番にも気を付けなければなりません。
2.グループ化
Pandasではグループ化をgroupby
メソッドを用いることで行うことが出来ます。
そもそもグループ化は何ぞやという人のために説明すると、
例えば『性別ごとの年齢の平均』を出したいとします。
この時の『〜ごとの、〜ごとに』をコード上で表現するために使われるのが、
groupby
メソッドです。
①単独のカラムでグループ化したい場合
df.groupby('グループ化したいカラム')
②複数のカラムでグループ化したい場合
df.groupby(['グループ化したいカラム1', 'グループ化したいカラム2',・・・])
はい、毎度恒例の複数のカラム選択の場合はリスト化ってやつですね!
今回は、乗客の性別ごとの平均年齢を出してみたいと思います。
#性別ごとの平均年齢の算出
df.groupby('Sex')['Age'].mean()
コードが少々見づらい、理解しづらいと思う方はdf.groupby('Sex')
で一つの塊のdf
と考えれば、納得できるのではないでしょうか?
3.カラム名の変更
元データのカラム名を変更して、より直感的にわかりやすいカラム名に変更したいことは、
しばしばあることです。そんな時はrename
メソッドを使用します。
df.rename(columns={'変更前のカラム名': '変更後のカラム名'}, inplace=True)
inplace=True
:元のdf
が変更され、新しいdf
を作成せずに変更が反映される。
inplace=False
:新しいdf
が返されるが、元のdf
は変更されない。
では、PclassをPassengerClassにSexをGenderに変更してみましょう。
#PclassとSexのカラム名を変更
df.rename(columns={'Pclass': 'PassengerClass', 'Sex': 'Gender'}, inplace=True)
#新しいdfの出力
df
カラム名が変更されていることが確認できますね!
inplace
のTrue
とFalse
はしっかりと区別しましょう。
4.locとilocを使った行・列指定
loc
とiloc
を使用すれば、より詳細に行・列の指定がしやすくなります。
loc
メソッド:
ラベルベースのインデックスを使用してデータを選択します。
2~5までの行とカラム1とカラム2の列を選択
df.loc[2:5, ['カラム1', 'カラム2']]
iloc
メソッド:
整数ベースのインデックスを使用してデータを選択します。
2~5までの行とカラム1(1列目)とカラム2(2列目)の列を選択
df.loc[2:6, [0, 1]]
それでは、両方のメソッドを使用して「2~5行目までのPclass,Name,Ageの列」を抽出しましょう。
# locメソッドを使用して特定の行と列を選択
df.loc[2:5, ['Pclass', 'Name', 'Age']]
#ilocメソッドを使用して特定の行と列を選択
df.iloc[2:6, [2, 3, 5]]
5.queryメソッドによる抽出
この章の最後にquery
メソッドを扱います。
『条件に基づくフィルタリング』で扱った内容とゴールは同じですが、書き方が少々異なります。
SQLに慣れている人は、このメソッドの方が使いやすいのではないでしょうか?
df.query("条件式")
それでは、『条件に基づくフィルタリング』の時と同様に「生存した女性」をQueryメソッドを使って出してみましょう。
#queryメソッドを使った抽出(フィルタリング)
df.query("Sex == 'female' and Survived == 1")
ちゃんと狙い通りのフィルタリングがされていますね!
ちなみに和集合(または条件)の時はor
とします。これも復習ですね?
6.文字列の数値化
この章の締めくくりに文字列の数値化を行いたいと思います。
具体的にはSexのカラムがmale→1,female→0とするわけです。これは機械学習よりの話になっていしまいますが、機械学習をさせるには読み込む特徴量は文字列ではなく数字でなければなりません。
このように文字列で表現されたカテゴリを、
値(数字)に変化することをカテゴリ変数化と言います。
from sklearn.preprocessing import LabelEncoder
# Sexを数値化
le_sex = LabelEncoder()
df_data['Sex'] = le_sex.fit_transform(df['Sex'])
# 数値化後のデータを10個表示
df_data.head(10)
性別のカラムが数字で表現されていますね!
こちらに関しては、データ分析というよりは機械学習で求められる操作ですね。
これから先のために覚えておいて下さい😎
第3章:データのグラフ化
下準備
この章から遂にデータの可視化に入っていきます。
以下のライブラリをインポートしておきましょう!
import seaborn as sns
import matplotlib.pyplot as plt
matplotlib:
Pythonのグラフの描画ためのライブラリです。Pandasだけでも簡単な描画はできますが、matplotlibを使うとより柔軟なグラフ描画が可能になります。
seaborn:
matplotlibをベースとした、データ可視化ライブラリです。matplotlib単体よりも、さらに豊富なパターンの可視化機能を有しており、かつ美しく鮮明な見た目も特徴です。
これらのライブラリを組み合わせて使用することで、データの可視化や解析を効果的かつ美しく行うことができます🤩
棒グラフ
まず最初は皆さんお馴染みの棒グラフです。
カテゴリー毎の数量の比較や時系列データなど幅広く活躍してくるグラフです。
今回は乗客の社会経済的地位を示すクラス(Pclass)を横軸、人数を縦軸として出力してみます。
# Pclassごとの乗客数を取得
pclass_counts = df_data['Pclass'].value_counts()
# 棒グラフの作成
plt.figure(figsize=(8, 6))
sns.barplot(x=pclass_counts.index, y=pclass_counts.values, palette="viridis")
plt.title('Passenger Count by Pclass')
#軸のタイトルを命名
plt.xlabel('Pclass')
plt.ylabel('Passenger Count')
#棒グラフ出力
plt.show()
長所
・視覚的な理解が容易 ・異なるカテゴリー間の比較が容易
・時系列データにも使える
短所
・比率の情報が薄い ・連続データには向かない ・大量のデータには向かない
使用例としては、『各地域の年間降水量の比較』や『異なるブランドの製品売上の比較』などのカテゴリー分けされ且つ絶対量で見たいものに最適です。
ヒストグラム
ヒストグラムは度数分布表の度数を縦軸、階級を横軸に持ってきたものです。
では横軸を年齢、縦軸を人数にとして出力してみましょう。
# Ageのヒストグラムを作成
# サイズを指定
plt.figure(figsize=(8, 6))
sns.histplot(df_data['Age'].dropna(), bins=30, kde=False, color='skyblue')
plt.title('Histogram of Age')
plt.xlabel('Age')
plt.ylabel('Frequency')
plt.show()
長所
・分布の理解が容易 ・中央傾向が把握しやすい ・異常値の発見が容易
短所
・階級の選択の影響を受ける ・個々データの損失 ・外れ値への敏感性
使用例としては、『人口の年齢分布』や『製品の品質管理における寸法のばらつき』などの、データに幅を持たせての"小さいグループ(階級)"ごとの比較に便利です。
円グラフ
こちらもお馴染みのグラフですね。
直感的にわかりやすい一方で、項目(カテゴリー)が増えると非常に見辛くなりますから注意です。
では、男女の比率を円グラフで見てみましょう。
# Sexごとのデータを集計
sex_counts = df_data['Sex'].value_counts()
# 円グラフの作成
plt.figure(figsize=(4, 4))
plt.pie(sex_counts, labels=sex_counts.index, autopct='%1.1f%%', startangle=90, colors=['skyblue', 'lightcoral'])
#タイトルの命名
plt.title('Passenger Distribution by Sex')
plt.show()
長所
・直感的に理解できる ・比率が瞬時に読み取れる
短所
・絶対量の情報が消える ・視覚的に項目数に限度がある
・不連続データに向かない ・僅かな比率の差が捉えにくい
使用例としては、『企業の売上高における各製品ラインの割合』や『市場調査での消費者の好みの分布』などの少数カテゴリー分類されるものに最適です。
箱ひげ図
なんか響きが懐かしいですよね箱ひげ図。。
私は高校の先生に、箱から髭が生えているから「箱ひげ図」なんだと教わりましたが、縦線が線が全て髭なんだみたいな教わり方もあるようです。
見方としては、縦線が重要です。縦線を左から見ていって、
1本目:最小値 2本目:第一四分位数
3本目:中央値 4本目:第三四分位数 5本目:最大値
ヒストグラムなどを描かずとも、山がどの辺りで膨らんでいるのか把握できます。
それでは、箱ひげ図で年齢の分布を見ていきましょう。
# Ageの箱ひげ図を作成
plt.figure(figsize=(8, 3))
sns.boxplot(x='Age', data=df, orient='h', color='skyblue')
#タイトルの命名
plt.title('Boxplot of Age')
plt.show()
長所
・複数のデータセットの比較に最適 ・分散, 外れ値, 中央値を示せる
短所
・前提知識を必要とする ・平均値や最頻値は直接示せない
出力結果に関してですが、最大値を示す右側にプロットされている⚪︎は外れ値を示しています。
使用例としては、『異なるクラスの試験成績の比較』や『複数地域の気温変動の比較』などの異なるグループ間の比較に最適です。
散布図
続いては散布図です。
集約メソッドの所で扱った相関係数と一緒に使われるグラフです。つまりこのグラフは二つの変数の相関関係を調べるときに役立ちます。
では、横軸を年齢, 縦軸を乗船料金として散布図を描いてみましょう。
# AgeとFareの散布図を作成
plt.figure(figsize=(8, 6))
sns.scatterplot(x='Age', y='Fare', data=df, color='coral', alpha=0.5)
plt.title('Scatter plot of Age vs Fare')
plt.xlabel('Age')
plt.ylabel('Fare')
plt.show()
長所
・二つの変数の関係が視覚的に理解できる
・データのパターンや傾向を把握しやすい
短所
・三つ以上の変数を扱うのが難しい ・データのプロットが重なると読みづらい
今回、「若い人ほど安いチケットを買って、年配の人ほど高いチケットが買える」という正の相関を予測して、カラム選択を行いましたが、ちょっと予測が外れてしまいましたね😭
集約メソッドの相関係数のところで紹介しましたが、正の相関が強い程データのプロットは傾きが1の直線上に並び、負の相関が強い程傾きが−1の直線上に並びます!
散布図行列
さあ、やってきました最後の学習項目です!ここまで一気に通した方はお疲れかと思いますが、本当に最後です!私もこれまで通り、気合を入れて書いておりますので、最後の最後までお付き合いよろしくお願いしますm(__)m
散布図の短所のところで、『三つ以上の変数を扱うのが難しい』と言いました。確かに、全ての変数に対して散布図を出力するのはあまりに面倒過ぎますよね?途中で「あれ?何やってっけ?」となるのが目に見えてますね?笑
そんな時に使える方法をご紹介したいと思います!以下のように入力してみましょう!
# 散布図行列を作成
sns.pairplot(df)
plt.show()
なんか凄いですよね笑笑
見てわかる通り、全てのカラムの組み合わせによる散布図がこんなに短い手順で出力されてしまいました!!
これを使えば、今まで気付けなかった意外な相関関係にも気付けそうですよね👍
第4章:最後に
いかがだったでしょうか?
Pandasは結構直感的になんとなく理解しやすいものですので、もういけそうな感じがしませんか?
今回の記事でPandasの全てのメソッドを扱ったわけではありませんが、これから自学自習するフェーズにおいて、何も手が出せないということはなくなったはずです。あとは、皆さんが各々知識の補填をしていくことで、本当にPandasをものにしたと言えます。
次は実際にKaggleでタイタニック号の生存予測のモデルを組んでも良いですし、統計学をPythonを使いながら学んでいっても良いでしょう。
どの道にしろ、やっぱり手を動かすことが大事です!
自分の手で「この部分だけ実行したらどうなるんだ?」とか「ここを変えたらどうなる?」とある種の実験をしていきます。そうすると「あ!こういうことかも!」と、またある種の仮説が出来ます。その仮説が芯を食う場合もあれば、また他の混乱を呼ぶこともあります。しかし、この過程を踏むことが何だかんだ近道であると私は思います。ですから、暗記暗記と考えず「まぁそのうち覚えるでしょ」という楽な感覚で取り組んでみてください。
ここまでお付き合い頂き、ありがとうございました。
弊社Nucoでは、他にも様々なお役立ち記事を公開しています。よかったら、Organizationのページも覗いてみてください。
また、Nucoでは一緒に働く仲間も募集しています!興味をお持ちいただける方は、こちらまで。