はじめに
「Python2年生 データ分析のしくみ 体験してわかる! 会話でまなべる!」で学習したので
備忘録として記載しています。
データ分析とは
客観的な事実をもとにして、よりよい解決方法を見つけること。
統計学とは、大量のデータから傾向を見つけ出して、法則を発見するための技術。
データ分析で必要なのは、データから推測する力と、分析結果を使って説明できる力。
データ分析の手順(PPDAC)
①Problem(問題の把握)
②Plan(調査の計画)
③Data(データの収集)
④Analysis(データの分析)
⑤Conclusion(結論を考える)⇒①へ戻る
表データ
横方向・・・1行、レコード、ロウ(row)
縦方法・・・1列、カラム(columns)
データフレーム
データフレームとはpandas
が用意するデータ形式で、Excelのように行と列で管理できる。
「データフレーム = pd.DataFrame(data)」のように指定する。
データフレームの作成
●行データからデータフレームを作る
data = [[1行目データ], [2行目データ], [3行目データ]]
データフレーム = pd.DataFrame(data)
データフレーム.columns = [列名のリスト]
データフレーム.index = [インデックス名のリスト]
※始めから列名とインデックス名を設定しておく場合は、下記を記載する。
col = [列名のリスト]
idx = [インデックス名のリスト]
import pandas as pd
# 行データからデータフレームを作る
data = [
[60, 65, 66], # 国語:60、数学:65、英語:66
[80, 85, 88],
[100, 100, 100]
]
col = ["国語", "数学", "英語"] # カラム名の作成
idx = ["A", "B", "C"] # インデックス名の作成
df = pd.DataFrame(data, columns=col, index=idx)
df
●列データからデータフレームを作る
data = {"列名":[列データ], "列名":[列データ], "列名":[列データ]}
idx = [インデックス名のリスト]
データフレーム = pd.DataFrame(data, index=idx)
import pandas as pd
# 列データからデータフレームを作る
data = {
"国語" : [60, 80, 100],
"数学" : [65, 85, 100],
"英語" : [66, 88, 100]
}
idx = ["A", "B", "C"] # インデックスを作成
df = pd.DataFrame(data, columns=col, index=idx)
df
CSVファイルを読み込む
CSVファイルには、「UTF-8形式」と「Shift-JIS形式」がある。
DataFrame = pd.read_csv("ファイル名.csv")
DataFrame = pd.read_csv("ファイル名.csv", encoding="Shift_JIS")
●0列目をインデックスを読み込む
DataFrame = pd.read_csv("ファイル名.csv", index_col=0)
●ヘッダーがない状態で読み込む
DataFrame = pd.read_csv("ファイル名.csv", header=None)
列(columns)、インデックスの確認
●列(columns)の確認
df.columns
●インデックスの確認
df.index
●列(columns)、インデックスをリストに変換する
# 列名をリスト変換
list1 = [i for i in df.columns]
print(list1)
# インデックス名をリスト変換
list2 = [i for i in df.index]
print(list2)
●各列のデータ種類の確認
df.dtypes
●データ個数の確認
len(df)
列データや行データを取り出す
●列データを取り出す
df["列名"]
df[["列名", "列名"]]
●行データを取り出す
df.iloc[行番号]
df.iloc[行番号, 行番号]
●要素データを取り出す
df.iloc[行番号]["列名"]
列データや行データを追加する
●空のデータフレームを作る
データフレーム = pd.DataFrame()
●列データを追加する
データフレーム["新列名"] = 列データ
●プログラム例
import pandas as pd
dfA = pd.read_csv("test.csv", index_col=0)
dfB = pd.DataFrame() # 空のデータフレームを作成
dfB["国語"] = dfA["国語"] # dfAをdfBへ代入
dfB # dfBを表示
●行データを追加する
データフレーム = データフレーム.append(列データ)
●プログラム例
import pandas as pd
dfA = pd.read_csv("test.csv", index_col=0)
dfB = pd.DataFrame()
dfB = dfB.append(dfA.iloc[0])
dfB
appendメソッドを実行すると、下記のアラートが出る
The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
列データや行データを削除する
●列データを削除する
データフレーム.drop("列名", axis=1)
●プログラム例
import pandas as pd
dfA = pd.read_csv("test.csv", index_col=0)
dfA = dfA.drop("国語", axis=1)
dfA
●行データを削除する
データフレーム.drop("行名")
●プログラム例
import pandas as pd
dfA = pd.read_csv("test.csv", index_col=0)
dfA = dfA.drop(dfA.index[3])
dfA
条件でデータを抽出する
●列データから「ある条件に合うデータを抽出する」
データフレーム["列名"] = 値
データフレーム["列名"] > 値
データフレーム["列名"] < 値
データフレーム = データフレーム[条件]
●プログラム例
import pandas as pd
dfA = pd.read_csv("test.csv", index_col=0)
dfA["国語"] > 80 # 国語が80より大きいか、True、Falseで表示
●プログラム例(抽出)
import pandas as pd
dfA = pd.read_csv("test.csv", index_col=0)
dfB = dfA[dfA["国語"] > 80] # 国語が80より大きいか抽出し、dfBへ代入
dfB
●プログラム例(複数の条件で抽出)
import pandas as pd
dfA = pd.read_csv("test.csv", index_col=0)
# 国語が80より大きいかつ数学が80より大きい条件で抽出し、dfBへ代入
dfB = dfA[(dfA["国語"] > 80) & (dfA["数学"] > 80)]
dfB
データの欠損値をチェックする
pandas
では「データが抜けていること」をNaN(ナン)と表示する。
これを欠損値という。
●プログラム例(NaNと表示)
import pandas as pd
# 列データからデータフレームを作成
data = {
"国語" : [90, 50, None, 40],
"数学" : [80, None, None, 50]
}
# インデックス名を作成
idx = ["A", "B", "C", "D"]
dfA = pd.DataFrame(data, index=idx)
dfA
●欠損値の個数
データフレーム.isnull().sum()
●プログラム例
dfA.isnull().sum() # 列データから個数を数える
●欠損値がある行を削除
※値がある行も合わせて削除される場合がある
データフレーム = データフレーム.dropna()
●プログラム例
dfB = dfA.dropna() # 欠損値がある行を削除し、dfBへ代入
dfB # dfBを表示
●欠損値がある行だけを削除
データフレーム = データフレーム.dropna(subset=["列名"])
●プログラム例
dfB = dfA.dropna(subset=["国語"]) # 国語データで欠損値がある行のみを削除し、dfBへ代入
dfB # dfBを表示
●欠損値を平均値で埋める
データフレーム = データフレーム.fillna(データフレーム.mean())
●プログラム例
dfB = dfA.fillna(dfA.mean())
dfB
●欠損値を1つ前の値で埋める
データフレーム = データフレーム.fillna(method='ffill')
●プログラム例
dfB = dfA.fillna(method='ffill')
dfB
重複したデータを削除する
●プログラム例
import pandas as pd
data = [
[10, 30, 40],
[20, 30, 40],
[20, 30, 40],
[30, 30, 50],
[20, 30, 40]
]
dfA = pd.DataFrame(data)
dfA
●重複データの個数
データフレーム.duplicated().value_counts()
●プログラム例
dfA.duplicated().value_counts()
# False 3
# True 2 ※重複するデータが2つある
# dtype: int64
●重複データの2つ目以降を削除する
データフレーム.drop_duplicates()
●プログラム例
dfB = dfA.drop_duplicates()
dfB
文字列型のデータを数値に変換する
●プログラム例
import pandas as pd
# 列データからデータフレームを作成
data = {
"A" : ["100", "300"],
"B" : ["500", "1,500"]
}
dfA = pd.DataFrame(data)
dfA
dfA.dtypes # データの種類を調べる
# A object
# B object
# dtype: object
●文字列の列データを整数に変換する
データフレーム["列名"] = データフレーム["列名"].astype(int)
●プログラム例
dfA["A"] = dfA["A"].astype(int) # A列を整数へ変換
dfA.dtypes # データの種類を調べる
# A int32
# B object
# dtype: object
●カンマ付き文字列の列データのカンマを削除する
データフレーム["列名"] = データフレーム["列名"].str.replace(",", "")
●プログラム例
dfA["B"] = dfA["B"].str.replace(",", "").astype(int) # カンマ付きのB列を整数に変換
dfA.dtypes # データの種類を調べる
# A int32
# B int32
# dtype: object
平均値を求める
代表値の一つに平均値があります。
平均値
とは、凹凸のあるデータの、凹凸を平らに均した値のこと。
「平均値 = データの合計 / データの個数」
●プログラム例
import pandas as pd
# 列データからデータフレームを作成
data = {
"A" : [82, 89, 93, 85, 76],
"B" : [100, 62, 82, 70, 86]
}
df = pd.DataFrame(data)
df
●列データの平均値を求める
df["列名"].mean()
●プログラム例
# A、Bの平均値を求める
print("A =", df["A"].mean())
print("B =", df["B"].mean())
# A = 85.0
# B = 80.0
代表値は、「データの比較」に使う
このように求めた代表値は、「データの比較」に使います。
「代表値と、代表値を比較」すると「グループとグループの差」がわかります。
●各列データの平均値を求める
df.mean()
●プログラム例
print(df.mean())
# A 85.0
# B 80.0
# dtype: float64
●プログラム例(代表値と、1つのデータを比較)
# 「A」の「0番目」と「A」の平均値を比較する
print(df.iloc[0]["A"])
print("A =", df["A"].mean())
# 82
# A = 85.0
# この結果から、「0番目」はAの平均値以下であることがわかる
代表値は「データの比較」に使う
・ 代表値と、別の代表値を比較:グループとグループの差がわかる
・ 昔の代表値と、今の代表値を比較:グループの変化がわかる
・ 代表値と、1つのデータを比較:1つのデータが全体のどのあたりなのかがわかる
平均値を代表としていいか調べる
平均値は、外れ値の影響を受けやすいという性質がある。
「平均値より外れ値の影響を受けにくい」代表値が必要となる場合もある。
それが、中央値と最頻値です。
・ 中央値:データを順番に並べたとき、ちょうど真ん中に来る値
・ 最頻値:データの中で一番多く現れる(最頻)値
●プログラム例
import pandas as pd
# 列データからデータフレームを作成
data = {
"予想価格" : [240, 250, 150, 240, 300, 5000]
}
df = pd.DataFrame(data)
df
●プログラム例(平均値を求める)
print(df.mean())
# 予想価格 1030.0
# dtype: float64
●各列データの中央値を求める
df.median()
●プログラム例(中央値を求める)
print(df.median())
# 予想価格 245.0
# dtype: float64
●各列データの最頻値を求める
df.mode()
●プログラム例(最頻値を求める)
print(df.mode())
# 予想価格
# 0 240
平均値、中央値、最頻値の違い
平均値
・ すべてのデータを考慮した値
・ 外れ値の影響を受けやすい
・ 標準偏差との相性がいいのでよく使われる
中央値
・ データを順番に並べたとき、ちょうど真ん中に来る値
・ 外れ値の影響をあまり受けにくい
最頻値
・ データの中で一番多く現れる(最頻)値
・ 外れ値の影響をあまり受けにくい
・ サンプル数が少ないと使えない
データのばらつきを調べる
データのばらつき方を表にして調べるときは、度数分布表を使います。
・ 階級:たくさんのデータをいくつかの範囲で区切った際の、区切った範囲のこと。
・ 度数:区切った範囲内にデータがいくつ入っているか、個数のこと。
・ 度数分布表:度数を表にして、データの分布をわかるようにしたもの。度数分布表を見ると、「データはどこからどこまであって」「全体が均等にばらついているのか、どこかだけに集中しているのか」などがわかる。
●プログラム例
import pandas as pd
# 列データからデータフレームを作成
data = {
"A" : [1, 10, 1, 10, 1, 10, 1, 10],
"B" : [5, 5, 5, 5, 6, 6, 6, 6],
"C" : [1, 2, 3, 4, 7, 8, 9, 10]
}
df = pd.DataFrame(data)
df
●プログラム例(平均値を求める)
print(df.mean())
# A 5.5
# B 5.5
# C 5.5
# dtype: float64
●プログラム例(中央値を求める)
print(df.median())
# A 5.5
# B 5.5
# C 5.5
# dtype: float64
●プログラム例(最頻値を求める)
print(df.mode())
# A B C
# 0 1.0 5.0 1
# 1 10.0 6.0 2
# 2 NaN NaN 3
# 3 NaN NaN 4
# 4 NaN NaN 7
# 5 NaN NaN 8
# 6 NaN NaN 9
# 7 NaN NaN 10
●列データの度数分布表を表示する
# pd.cut()でいくつかの範囲に区切る
cut = pd.cut(df["列名"], bins=区切る範囲, right=False)
# cut.value_counts()でそれぞれの範囲にいくつデータが入っているかカウントする
cut.value_counts(sort=False)
●プログラム例(Aの度数分布表を表示)
# 「1~3, 3~5, 5~7, 7~9, 9~11」の範囲を作成
bins = [1, 3, 5, 7, 9, 11]
# 「right=False」で「範囲の左側は含まれるが、右側は含まれない」という設定にする。
# 「1以上3未満、3以上5未満、5以上7未満、7以上9未満、9以上11未満」の範囲を作成している。
cut = pd.cut(df["A"], bins=bins, right=False)
cut.value_counts(sort=False)
# [1, 3) 4 # 1以上3未満
# [3, 5) 0 # 3以上5未満
# [5, 7) 0 # 5以上7未満
# [7, 9) 0 # 7以上9未満
# [9, 11) 4 # 9以上11未満
# Name: A, dtype: int64
データのばらつきがわかる
matplotlibの使い方について
グラフを表示するときは、matplotlibライブラリを使います。
「import matplotlib.pyplot as plt」と命令すると、matplotlibを「plt」という省略形で扱えます。
●グラフは主に3段階で命令します。
1.「どんなデータで、何のグラフを表示するか」を決める。
2.必要なときは、「タイトルや線などの追加情報」を指定する。
3.最後に「plt.show()」と命令すると、指定したグラフが表示される。
matplotlibのグラフは、Pythonでは別ウィンドウで表示されるのですが、
Jupter Notebookでは、「%matplotlib inline」と指定して、Jupter Notebook中に
グラフを表示させます。
●プログラム例(入力プログラム)
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot([0, 100, 200], [100, 0, 200])
plt.show()
# グラフが表示される
seabornの使い方について
さらにグラフをきれいに描写するライブラリです。
seabornライブラリは、matplotlibを拡張するライブラリなので、使うときは両方をimportします。
「import seaborn as sns」と命令すると、「sns」という省略形で扱えます。
seabornは、最初に「sns.set()」と命令しておくだけで
これ以降に表示されるグラフがきれいに表示されます。
さらに、フォント指定も簡単で、「sns,set(font=["フォント名"])」と命令するだけで設定できます。「sns,set(font=["Meiryo", "Yu Gothic", "Hiragino Maru Gothic Pro"])」と命令するだけで、日本語が使えるようになります。
●プログラム例(入力プログラム)
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Meiryo", "Yu Gothic", "Hiragino Maru Gothic Pro"])
plt.plot([0, 100, 200], [100, 0, 200])
plt.title("タイトル")
plt.show()
# グラフが表示される
seabornのスタイルの変更
「sns.set(style="スタイル", font=["Meiryo", "Yu Gothic", "Hiragino Maru Gothic Pro"])」と命令します。
スタイルには、"dark"(暗色),"darkgrid"(暗い色で線あり),
"white"(白),"whitegrid"(白で線あり),"ticks"(目盛りあり)などを指定できます。
データのばらつきがわかる:ヒストグラム
●プログラム例(入力プログラム)
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Meiryo", "Yu Gothic", "Hiragino Maru Gothic Pro"])
# 列データからデータフレームを作成
data = {
"A": [1, 10, 1, 10, 1, 10, 1, 10],
"B": [5, 5, 5, 5, 6, 6, 6, 6],
"C": [1, 2, 3, 4, 7, 8, 9, 10]
}
df = pd.DataFrame(data)
df
# 表が作成される
◆データ分析の命令:列データのヒストグラムを表示する
・ 必要なライブラリ:pandas、matplotlib、(seaborn)
・ 命令
df["列名"].plot.hist(bins=区切る範囲)
plt.show()
・ 出力:列データのばらつきがわかるヒストグラム
●プログラム例(入力プログラム)
# 区切る範囲を指定
bins = [1,3,5,7,9,11]
df.plot.hist(bins=bins)
# タイトルを作成
plt.title("ケーキの感想はどのように違うか?")
plt.show()
# グラフが表示される
◎ヒストグラムは度数分布表をグラフ化したもの。
グラフを作る前に「何のためのグラフなのか」を意識して、グラフが表示されたら
「ここから何が読み取れるか」を考える。この積み重ねで、ただの客観的なデータが、
人間にとって意味のあるデータになってくる。
●プログラム例(入力プログラム)
# Aのグラフを作成
df["A"].plot.hist(bins=bins)
plt.title("Aのケーキの感想")
plt.show()
# Bのグラフを作成
df["B"].plot.hist(bins=bins)
plt.title("Bのケーキの感想")
plt.show()
# Cのグラフを作成
df["C"].plot.hist(bins=bins)
plt.title("Cのケーキの感想")
plt.show()
# グラフが表示される
基本的なグラフを作る
大小を比較できる:棒グラフ
棒グラフは「数量の大小を比較できるグラフ」です。
「棒の高さ」がそれぞれの量を表しています。
「それぞれ独立した値を比較するとき」に使います。
●プログラム例(入力プログラム)
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Meiryo", "Yu Gothic", "Hiragino Maru Gothic Pro"])
# 列データからデータフレームを作成
data = {
"名前": ["A", "B", "C"],
"国語": [60, 80, 100],
"数学": [65, 85, 100],
"英語": [66, 88, 100]
}
df = pd.DataFrame(data)
df
# 表が作成される
このデータを棒グラフで表示してみます。
棒グラフにするには、「データフレーム.plt.bar()」と命令します。
◆データ分析の命令(列データの棒グラフを表示する)
・ 必要なライブラリ:pandas、matplotlib、(seaborn)
・ 命令
df.plot.bar()
plt.show()
・ 出力:列データの棒グラフ
●プログラム例(入力プログラム)
# 棒グラフで表示
df.plot.bar()
# タイトルを作成
plt.title("3名の成績")
plt.show()
# 棒ブラフが作成される
数値データの「国語」「数学」「英語」の列がグラフ化されました。ただし、
文字列データの「名前」の列はグラフ化できないので、自動的に表示対象から外されています。
グラフの横軸をみると、インデックス番号が表示されています。
「名前」の列を、インデックスに使う。「df.set_index("列名", inplace=True)」で指定します。
●プログラム例(入力プログラム)
# インデックスの置き換え
df.set_index("名前", inplace=True)
df
# 表が作成される
●プログラム例(入力プログラム)
df.plot.bar()
plt.title("3名の成績")
plt.show()
# 棒ブラフの横軸が変更される
「df["列名"]」と指定すると、特定の列データのみだけでグラフを表示できます。
●プログラム例(入力プログラム)
df["国語"].plot.bar()
plt.title("国語の成績")
plt.show()
# 国語のみの棒ブラフが表示される
変化がわかる:折れ線グラフ
折れ線グラフは「時間的な値の変化がわかるグラフ」です。
時間で変化するデータに使うので、項目名が「年、月、日、時、分」になっているなど
「時系列に並んでいるデータ」に使います。
●プログラム例(入力プログラム)
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Meiryo", "Yu Gothic", "Hiragino Maru Gothic Pro"])
# 列データからデータフレームを作成
data = {
"月": [1,2,3,4,5,6,7,8,9,10,11,12],
"東京": [5.6, 7.2, 10.6, 13.6, 20.0, 21.8, 24.1, 28.4, 25.1, 19.4, 13.1, 8.5],
"那覇": [18.1, 20.0, 19.9, 22.3, 24.2, 26.5, 28.9, 29.2, 28.0, 26.0, 23.1, 20.0],
"札幌": [-3.0, -2.6, 2.5, 8.0, 15.7, 17.4, 21.7, 22.5, 19.3, 13.3, 3.9, -0.8]
}
df = pd.DataFrame(data)
df
# 表が表示される
インデックスと月の数字がずれているので、「月」の列を、インデックスとして指定します。
●プログラム例(入力プログラム)
df.set_index("月", inplace=True)
df.head()
# 表が表示される
このデータを折れ線グラフで表示してみます。
折れ線グラフにするには、「データフレーム.plot()」と命令します。
◆データ分析の命令:列データの折れ線グラフを表示する
・ 必要なライブラリ:pandas、matplotlib、(seaborn)
・ 命令
df["列名"].plot()
plt.show()
・ 出力:列データの折れ線グラフ
●プログラム例(入力プログラム)
df.plot()
plt.title("日本の気温の変化")
plt.show()
# 折れ線グラフが表示される
「df["列名"]」と指定すると、特定の列データのみだけでグラフを表示できます。
●プログラム例(入力プログラム)
df["東京"].plot()
plt.title("東京の気温の変化")
plt.show()
# 東京の折れ線グラフが表示される
要素の割合を比較できる:円グラフ
円グラフは「全体に対する要素の割合がわかるグラフ」です。
「すべての要素の値を合計して100%になるデータ」に使います。
●プログラム例(入力プログラム)
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Meiryo", "Yu Gothic", "Hiragino Maru Gothic Pro"])
data = {
"クッキー": [35,47,18],
"ケーキ": [62,26,12]
}
idx = ["好き", "普通", "嫌い"]
df = pd.DataFrame(data, idx)
df
# 表が作成される
このデータを円グラフで表示してみます。
円グラフにするには、「データフレーム.plot.pie()」と命令します。
◆データ分析の命令:列データの円グラフを表示する
・ 必要なライブラリ:pandas、matplotlib、(seaborn)
・ 命令
df["列名"].plot.pie()
plt.show()
・ 出力:列データの円グラフ
●プログラム例(入力プログラム)
df["クッキー"].plot.pie()
plt.title("お菓子の好き嫌いは、どのような割合か?")
plt.show()
# 円グラフの表示
matplotlibの円グラフは、「右側から始まって反時計回り」に描かれます。
一般的な円グラフのように「真上から始まって時計回り」に描かれるように変更します。
オプションで「startangle=90,counterclock=False」と指定します。
文字を円グラフの内側に表示させるには、「labeldistance=0.5」を追加します。
●プログラム例(入力プログラム)
df["クッキー"].plot.pie(startangle=90, counterclock=False, labeldistance=0.5)
plt.title("お菓子の好き嫌いは、どのような割合か?")
plt.show()
# 円グラフの表示
棒グラフ・折れ線グラフ・円グラフの見分け方
データ->合計すると100%か?->円グラフ
->時系列に進んだデータか?->折れ線グラフ
->独立した値の比較か?->棒グラフ
ばらつきのわかるグラフ
データのばらつきを比較できる:箱ひげ図
箱ひげ図は「データのばらつきを比較できるグラフ」です。
複数のデータのばらつきを比較するときに使用します。
●プログラム例(入力プログラム)
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Meiryo", "Yu Gothic", "Hiragino Maru Gothic Pro"])
data = {
"A": [163.6, 172.6, 163.7, 167.1, 169.9, 173.9, 170.1, 166.2, 176.7, 165.4],
"B": [166.9, 172.7, 166.4, 173.4, 169.6, 171.8, 166.9, 168.2, 166.7, 169.8]
}
df = pd.DataFrame(data)
df
# 表が表示される
このデータを箱ひげ図で表示します。
箱ひげ図は、matplotlibにも「df.boxplot()」という命令がありますが、
seabornの「sns.boxplot(data=データフレーム, width=幅)」という命令のほうが、色付きで
きれいに表示されます。
◆データ分析の命令:列データの箱ひげ図を表示する
・ 必要なライブラリ:pandas、matplotlib、seaborn
・ 命令
sns.boxplot(data=df, width=幅)
plt.show()
・ 出力:各列データの箱ひげ図
●プログラム例(入力プログラム)
sns.boxplot(data=df, width=0.2)
plt.title("身長のばらつきに違いはあるか?")
plt.show()
# 箱ひげ図の表示
※出力結果から、「Aのほうがばらつきが大きく、Bのほうがまとまっている」、
「Aのほうが身長の高い生徒がいるが、中央値はBのほうが高い」とわかる。
●プログラム例(入力プログラム)
print(df.median()) # 中央値を出力
# A 168.5
# B 168.9
# dtype: float64
2種類のデータの関係性がわかる:散布図
散布図は「2種類のデータの関係性がわかるグラフ」です。
「あるデータと別のデータに関係性があるかを目で見て確認するとき」に使います。
●プログラム例(入力プログラム)
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Meiryo", "Yu Gothic", "Hiragino Maru Gothic Pro"])
data = {
"身長": [163.6, 172.6, 163.7, 169.9, 173.9, 166.2, 176.7, 165.4],
"体重": [50.5, 63.3, 48.5, 59.8, 69.8, 53.7, 70.3, 51.2]
}
df = pd.DataFrame(data)
df
# 表が作成される
このデータを散布図で表示します。
散布図を表示させるときは、「データフレーム.plot.scatter(x="横軸の列名", y="縦軸の列名", c="色")」と命令します。
◆データ分析の命令:散布図を表示する
・ 必要なライブラリ:pandas、matplotlib
・ 命令
df.plot.scatter(x="横軸の列名", y="縦軸の列名", c="色")
plt.show()
・ 出力:指定した列データの散布図
●プログラム例(入力プログラム)
df.plot.scatter(x="身長", y="体重", c="b")
plt.title("身長と体重に関係はあるか?")
plt.show()
# 散布図の表示
※出力結果から、点が右上がりのため、「身長が高いと、体重が重くなるので、関係がありそう」
とわかります。
グラフをわかりやすく調整する
グラフのある点を目立たせる
マーカーを表示するには、グラフを表示させた後に、「plt.plot(x座標, y座標, c="色", marker="マーカー", markersize=サイズ)」と命令して、マーカーを追加表示させることができます。
マーカーは、"o"(丸)、"X"(バツ)、"V"、"^"、"<"、">"などがあります。
◆データ分析の命令:グラフに目立つ1つの点を追加する
・ 必要なライブラリ:pandas、matplotlib
・ 命令
# グラフを表示するplotの命令
plt.plot(X座標, Y座標, c="色", marker="X", markersize=サイズ)
plt.show()
・ 出力:グラフに目立つ1つの点を追加する
●プログラム例(入力プログラム)
sns.set_context("talk")
df.plot.scatter(x="身長", y="体重", c="b", figsize=(12, 8))
# 「私」のデータが「3行目」にあるとする。
x = df.iloc[3]["身長"]
y = df.iloc[3]["体重"]
plt.plot(x, y, c="r", marker="X", markersize=15)
plt.title("私はどこにいるか")
plt.show()
グラフに線を引く
グラフを表示させたあとに、線を引く命令を追加します。
垂直線は「plt.axvline(x=X座標, c="色", linestyle="線の種類")」と、
水平線は「plt.axhline(y=Y座標, c="色", linestyle="線の種類")」と命令します。
◆データ分析の命令:グラフに垂直線、水平線を追加する
・ 必要なライブラリ:pandas、matplotlib
・ 命令
# グラフを表示するplotの命令
plt.axvline(x=X座標, c="色", linestyle="--")
plt.axhline(y=Y座標, c="色", linestyle="--")
plt.show()
・ 出力:グラフに垂直線(axvline)、水平線(axhline)を追加する
●プログラム例(入力プログラム)
sns.set_context("talk")
df.plot.scatter(x="身長", y="体重", c="b", figsize=(12, 8))
x = df.iloc[3]["身長"]
y = df.iloc[3]["体重"]
plt.plot(x, y, c="r", marker="^", markersize=15)
# 縦、横に線を引く
plt.axvline(x=x, c="r", linestyle="--")
plt.axhline(y=y, c="r", linestyle="--")
plt.show()
データのばらつきを数値で表す
「データのばらつき」は、「表」(度数分布表)や「グラフ」(ヒストグラム)で
見ることができましたが、「1つの数値」で知ることもできます。
それが「標準偏差」です。
「平均値が同じで、ばらつきが違う2種類のデータ」があります。
●プログラム例(入力プログラム)
import pandas as pd
data = {
"ID": [0,1,2,3,4,5,6,7,8,9],
"A": [59,24,62,48,58,19,32,88,47,63],
"B": [49,50,49,54,45,52,56,48,45,52]
}
df = pd.DataFrame(data)
# 平均値を出力
print(df["A"].mean())
print(df["B"].mean())
# 50.0
# 50.0
「散布図」を使って、データが散らばっている様子を点で表示します。
横軸に番号のID、縦軸に列データ名を指定して表示します。
比較したいので、「ylim=(0, 100)」と設定して、どちらも縦軸をそろえます。
さらに、平均値(50)に水平線を引いておきます。
●プログラム例(入力プログラム)
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Meiryo", "Yu Gothic", "Hiragino Maru Gothic Pro"])
df.plot.scatter(x="ID", y="A", color="b", ylim=(0, 100))
plt.axhline(y=50, c="Magenta")
plt.title("Aのばらつき:大きい", fontsize=24)
plt.show()
df.plot.scatter(x="ID", y="B", color="b", ylim=(0, 100))
plt.axhline(y=50, c="Magenta")
plt.title("Bのばらつき:小さい", fontsize=24)
plt.show()
出力結果から「上下にばらついている様子」がわかります。
これを「1つの数値」で表現するにはどうすればいいか。
上下のばらつきは、「各データと平均値の差」ですから、これらを合計して平均してみたいと
思います。つまり、「このデータ全体は、平均値からどれだけ上下にばらついているか」を「1つの数値」で表そうというわけです。
ただし、そのまま「差を合計」すると、0になってしまいます。
もともと「平均値は上下のばらつきが0になるように平らに均した値」だからです。
プラス部分とマイナス部分を打ち消しあって0になるのが問題なので、
マイナス部分をプラスにしようというアイデアが出できました。
「各データと平均値の差を2乗」すれば、マイナスがプラスになります。
これを「分散」といいます。
「データが分かれて散らばっている様子を表している」ので「分散」です。
計算では、「分散 = 平均値からの差の2乗の合計 ÷ データの個数」で求めます。
pandasで分散を求めるときは、「データフレーム.var()」と命令します。
◆データ分析の命令:各列データの分散を求める
・ 必要なライブラリ:pandas
・ 命令
df.var()
・ 出力:各列データの分散
●プログラム例(入力プログラム)
print(df.var())
# ID 9.166667
# A 430.666667
# B 12.888889
# dtype: float64
「2乗したのだから、平方根でもとの単位に戻す」⇒「標準偏差」
計算では、「分散の平方根」で求めます。
pandasでは、「データフレーム.std()」と命令します。
◆データ分析の命令:各列データの標準偏差を求める
・ 必要なライブラリ:pandas
・ 命令
df.std()
・ 出力:各列データの標準偏差
●プログラム例(入力プログラム)
print(df.var())
# ID 3.02765
# A 20.75251
# B 3.59011
# dtype: float64
出力結果から「0~100の間のデータで、Aは20.8もあるのだから、ばらつきがそこそこあり、Bは3.6なのでばらつきが小さい」とわかります。このように、標準偏差は
「もとの単位に合わせた1つの数値でデータのばらつきを表す」ことができます。
ある範囲にどのくらいデータがあるかがわかる
標準偏差は、「どのくらいばらついているか」がわかるだけでなく、分布がある形をしている場合には、「ある範囲にどのくらいデータがあるか」までわかります。
先ほどのAのデータの「平均値」と「標準偏差」を求めて、Aの範囲を求めてみます。
●プログラム例(入力プログラム)
meanA = df["A"].mean()
stdA = df["A"].std()
print(meanA - stdA, "~", meanA + stdA)
# 29.247490111635493 ~ 70.7525098883645
「Aのデータは約68%が、29.2~70.8の範囲にある」と結果が出ました。
Bのデータの「平均値」と「標準偏差」も求めて、Bの範囲を求めてみます。
●プログラム例(入力プログラム)
meanB = df["B"].mean()
stdB = df["B"].std()
print(meanB - stdB, "~", meanB + stdB)
# 46.409890128577 ~ 53.590109871423
「Bのデータは約68%が、46.4~53.6の範囲にある」と結果が出ました。
「ヒストグラム」の中では標準偏差はどのようになるのか。
まず、このデータをヒストグラムで表示してみます。
比較をしたいので、「ylim=(0, 6)」と設定して、どちらも縦軸をそろえます。
●プログラム例(入力プログラム)
bins = [10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100]
df["A"].plot.hist(bins=bins, color="c", ylim=(0, 6))
plt.title("Aのばらつき:大きい")
plt.show()
df["B"].plot.hist(bins=bins, color="c", ylim=(0, 6))
plt.title("Bのばらつき:小さい")
plt.show()
# ヒストグラムが表示される
ヒストグラムは、「横軸が階級で、縦軸が度数」です。
横軸は、そのデータが取り得る値なので、「平均値」も横軸のどこかにあります。
また、「約68%の範囲を表す値」も横軸のどこかにあるはずです。
「平均値」「平均値ー標準偏差」「平均値+標準偏差」の位置に垂直線を引いてみます。
●プログラム例(入力プログラム)
bins = [10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100]
df["A"].plot.hist(bins=bins, color="c", ylim=(0, 6))
plt.axvline(x=meanA, color="magenta")
plt.axvline(x=meanA - stdA, color="blue", linestyle="--")
plt.axvline(x=meanA + stdA, color="red", linestyle="--")
plt.title("Aのばらつき:大きい")
plt.show()
df["B"].plot.hist(bins=bins, color="c", ylim=(0, 6))
plt.axvline(x=meanB, color="magenta")
plt.axvline(x=meanB - stdB, color="blue", linestyle="--")
plt.axvline(x=meanB + stdB, color="red", linestyle="--")
plt.title("Bのばらつき:小さい")
plt.show()
# ヒストグラムが表示される
ヒストグラムで見ても「標準偏差の線ではさまれた範囲が、データの約68%の範囲を示している」ことがわかります。
自然なばらつき
「正規分布」とは、「自然界でごく普通の、よくある分布」という意味。
●なぜ正規分布は、自然界でごく普通の分布か?
「平均値付近のことはよく起こり、平均値から遠いとめったに起こらなくなる」
「自然界のものは正規分布になることが多い」ということと「カーブ(ガウス分布)は、計算で求めることができる」
「自然界のばらつきとは、誤差の積み重ねでできているのではないか」=「中心極限定理」
●ゴルトンボードをシュミレート
●プログラム例(入力プログラム)
%matplotlib inline
import random
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Meiryo", "Yu Gothic", "Hiragino Maru Gothic Pro"])
def galton(steps, count):
ans = []
for i in range(count):
val = 50
for j in range(steps):
if random.randint(0, 1) == 0:
val = val - 1
else:
val = val + 1
ans.append(val)
df = pd.DataFrame(ans)
df[0].plot.hist()
plt.title(str(steps)+"段:"+str(count)+"個")
plt.ylabel("")
plt.show()
galton(1, 10000)
# 結果表示
●正規分布は計算で求めることができる
「平均値」がわかれば、「正規分布の左右の位置」がわかります。
「標準偏差」がわかれば、「正規分布のカーブとがり具合」がわかります。
標準偏差が小さければ急なカーブに、大きければゆるやかなカーブになります。
つまり、「平均値と標準偏差がわかれば、正規分布の形がわかる」ということです。
計算でカーブの形がわかります。
そのカーブで囲まれた「ある範囲の面積」を計算で求めることもできます。
ヒストグラムは、面積がデータ量を表していますから、
この「面積の割合」はつまり「データの割合」です。
「真ん中(平均値)から、前後に標準偏差までの範囲に、全体のxx%のデータがある」など。
この値は普通なこと?珍しいこと?
scipy.statsライブラリに入っている正規分布用の関数を使うと、難しい計算が必要な数値も、
簡単に求めることができます。
例えば、「norm.cdf(正規分布の累積分布関数)」を使うと、
「ある値が、全体の下から何%のことなのか」を求めることができます。
用意するのは「調べたい値」「平均値」「標準偏差」の3つだけです。
「norm.cdf(x=調べたい値, loc=平均値, scale=標準偏差)」と命令すると、ある値が全体の下から何%のことなのかを0~1の値で返してくれます。
◆データ分析の命令:ある値は、下から何%に該当するか?
・ 必要なライブラリ:scipy.stats
・ 命令
cdf = norm.cdf(x=調べたい値, loc=平均値, scale=標準偏差)
・ 出力:ある値は、下から何%に該当するか?
例:「平均値が166.8cm、標準偏差が5.8cm」の正規分布のデータで
「160.0cmは下から何%の位置にあるか」
●プログラム例(入力プログラム)
from scipy.stats import norm
mean = 166.8
std = 5.8
value = 160.0
cdf = norm.cdf(x=value, loc=mean, scale=std)
print(value, "は、下から", cdf*100, "%")
# 160.0 は、下から 12.051548220947089 %
逆に、「ある値は、上から何%なのか」を調べるには、norm.cdfの値を
1(100%)から引けばわかります。
例:「平均値が166.8cm、標準偏差が5.8cm」の正規分布のデータで
「170.0cmは上から何%の位置にあるか」を「1-cdf」で求めてみる。
●プログラム例(入力プログラム)
from scipy.stats import norm
mean = 166.8
std = 5.8
value = 178.0
cdf = norm.cdf(x=value, loc=mean, scale=std)
print(value, "は、上から", (1-cdf)*100, "%")
# 178.0 は、上から 2.6739394108996173 %
「norm.ppf(正規分布のパーセント点関数)」を使うと、
「全体の下から〇〇%にあたる値は何か?」を求めることができます。
用意するのは「下から何%を調べたいか(0~1)」「平均値」「標準偏差」の3つだけです。
「norm.ppf(q=パーセント値, loc=平均値, scale=標準偏差)」と命令すると、
全体の下から〇〇%にあたる値は何かを返してくれます。
◆データ分析の命令:下から〇〇%にあたる値は何か?
・ 必要なライブラリ:scipy.stats
・ 命令
ppf = norm.ppf(q=パーセント値, loc=平均値, scale=標準偏差)
・ 出力:下から〇〇%にあたる値は何か?
例:「平均値が166.8cm、標準偏差が5.8cm」の正規分布のデータで
「下から20%は、何cmなのか」
●プログラム例(入力プログラム)
from scipy.stats import norm
mean = 166.8
std = 5.8
per = 0.20
ppf = norm.ppf(q=per, loc=mean, scale=std)
print("下から", per * 100, "%の値は、", ppf, "です。")
# 下から 20.0 %の値は、 161.9185968452771 です。
逆に、「上から〇〇%に該当する値は何なのか」を調べるには、norm.ppfに渡す確率を
1(100%)から引けばわかります。
例:「平均値が166.8cm、標準偏差が5.8cm」の正規分布のデータで
「上から1%は、何cmなのか」を「1-per」で求めてみる。
●プログラム例(入力プログラム)
from scipy.stats import norm
mean = 166.8
std = 5.8
per = 0.01
ppf = norm.ppf(q=(1-per), loc=mean, scale=std)
print("上から", per * 100, "%の値は、", ppf, "です。")
# 上から 1.0 %の値は、 180.2928176694369 です。
●違うばらつきのデータでの比較
「norm.cdf」を使うと、「違うばらつきのデータ」でどちらがより珍しいかを
調べることができます。
例:あるテストで数学60点、英語80点を取ったとします。
どちらががんばったでしょうか。
数学 | 英語 | |
---|---|---|
点数 | 60 | 80 |
平均値 | 50 | 70 |
標準偏差 | 5 | 8 |
平均値や標準偏差が違います。このようなとき「2つの点が上から何%の珍しいことか」を比べることで、どちらがよりがんばったのかを調べることができます。
●プログラム例(入力プログラム)
from scipy.stats import norm
scoreM= 60
meanM = 50
stdM = 5
scoreE = 80
meanE = 70
stdE = 8
cdf = norm.cdf(x=scoreM, loc=meanM, scale=stdM)
print("数学の", scoreM, "点は、上から", (1-cdf)*100, "%")
cdf = norm.cdf(x=scoreE, loc=meanE, scale=stdE)
print("英語の", scoreE, "点は、上から", (1-cdf)*100, "%")
# 数学の 60 点は、上から 2.275013194817921 %
# 英語の 80 点は、上から 10.564977366685536 %
この結果を見ると、英語は80点ですが上から10.6%でした。
数学は60点ですが上から2.3%なので、より珍しい点だったと分かります。これは数学ががんばったと考えられそうです。
このデータは自然なばらつき?
ヒストグラムは、matplotlibの「データフレーム.plot.hist(bins=bins)」で表示できましたが、seabornの「sns.distplot(データフレーム)」を使うとさらに便利な機能が付いてきます。
「もしもデータがもっとたくさんあったらどうなるか(カーネル密度推定)」という予測カーブを重ねて表示させることができます。
さらに「fit=norm」というオプションをつけると「もし、正規分布になるとしたらどんなカーブになるのだろう」というところまで推定して重ね合わせることまでできます。
◆データ分析の命令:列データのヒストグラムを表示する(正規分布、推定カーブ付き)
・ 必要なライブラリ:pandas、matplotlib、seaborn
・ 命令
sns.distplot(df["列名"], fit=norm, fit_kws={"color":"色"})
plt.show()
・ 出力:列データのヒストグラム
例として、Numpyライブラリを使ってデータを自動生成してみます。
「random.randit(最小値, 最大値, 最大値, 個数)」命令を使うと、
「最小値から最大値までのかたよりのない、ばらけたランダムな値」を作ることができます。「random.normal(平均値, 標準偏差, 個数)」命令を使うと、「中央が一番多い、正規分布になるようなランダムな値」を作ることができます。
●プログラム例(入力プログラム)
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from scipy.stats import norm
sns.set(font=["Meiryo", "Yu Gothic", "Hiragino Maru Gothic Pro"])
df = pd.DataFrame({
"A": np.random.randint(0, 100, 1500),
"B": np.random.normal(50, 10, 1500)
})
sns.distplot(df["A"], fit=norm, fit_kws={"color": "red"})
plt.title("かたよりのないランダムな値")
plt.show()
sns.distplot(df["B"], fit=norm, fit_kws={"color": "red"})
plt.title("正規分布になるようなランダムな値")
plt.show()
# グラフ表示
Aは正規分布とかなり違う。逆にBは、正規分布に近くなりました。
ただ正規分布はあくまで理想形なので、現実のデータはズレがあることを忘れずに!!
違うばらつきのデータでの比較ができる
●偏差値:真ん中は50
あらかじめ「平均値は50、標準偏差は10」とそろえることで、
比較しやすくする方法が考えられました。それが「偏差値」です。
「(自分の得点-平均点)÷標準偏差×10+50」で自分の偏差値を求めることができる。
例:偏差値60、70、80が上から何%となるか調べてみる。
●プログラム例(入力プログラム)
from scipy.stats import norm
scorelist = [60, 70, 80]
for score in scorelist:
cdf = norm.cdf(x=score, loc=50, scale=10)
print("偏差値", score, "は、上から", (1-cdf)*100, "%")
# 偏差値 60 は、上から 15.865525393145708 %
# 偏差値 70 は、上から 2.275013194817921 %
# 偏差値 80 は、上から 0.13498980316301035 %
逆に、上から何%に入るのに必要な偏差値は、「norm.ppf」で調べることができます。
例:上から、15.86%、2.2275%、0.134%に入るのに必要な偏差値を調べてみる。
●プログラム例(入力プログラム)
perlist = [0.1586, 0.02275, 0.00134]
for per in perlist:
ppf = norm.ppf(q=(1-per), loc=50, scale=10)
print("上から", per*100, "%以上に入るには、偏差値", ppf, "以上が必要")
# 上から 15.86 %以上に入るには、偏差値 60.002283757327085 以上が必要
# 上から 2.275 %以上に入るには、偏差値 70.00002443899604 以上が必要
# 上から 0.134 %以上に入るには、偏差値 80.02240904267309 以上が必要
●IQ:真ん中は100
あらかじめ「平均値は100、標準偏差は15(または24)」とそろえることで、
比較しやすくする方法が考えられました。それが「IQ(知能指数)」です。
例:IQ110、130、148が上から何%になるのか調べる。
●プログラム例(入力プログラム)
from scipy.stats import norm
std = 15
IQlist = [110, 130, 148]
for IQ in IQlist:
cdf = norm.cdf(IQ, loc=100, scale=std)
print("IQ", IQ, "は、上から", (1-cdf)*100, "%")
# IQ 110 は、上から 25.24925375469229 %
# IQ 130 は、上から 2.275013194817921 %
# IQ 148 は、上から 0.06871379379158604 %
今度は標準偏差24の場合を調べる。
●プログラム例(入力プログラム)
from scipy.stats import norm
std = 24
IQlist = [110, 130, 148]
for IQ in IQlist:
cdf = norm.cdf(IQ, loc=100, scale=std)
print("IQ", IQ, "は、上から", (1-cdf)*100, "%")
# IQ 110 は、上から 33.84611195106897 %
# IQ 130 は、上から 10.564977366685536 %
# IQ 148 は、上から 2.275013194817921 %
2種類のデータの関係性の強さ:相関係数
●散布図
これまでは、データの集まりを、1つの代表値にまとめたり、ばらつき方に注目してきました。
それぞれのデータを「切り離して、比較」することで調べましたが、
今度は「つながり(関係性)があるか」について見ていきます。
2種類のデータの関係性を見るには、「散布図」を使います。
横軸と縦軸に関係性を見たいデータを割り当てることで「この2種類のデータに、どのくらい関係性があるか」を見ることができます。
例:「数学と理科と社会」の成績データで、「数学と理科」「数学と社会」の関係性はあるか調べる。
●プログラム例(入力プログラム)
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Meiryo", "Yu Gothic", "Hiragino Maru Gothic Pro"])
data = {
"数学": [100, 85, 90, 95, 80, 80, 75, 65, 65, 60, 55, 45, 45],
"理科": [94, 90, 95, 90, 85, 80, 75, 70, 60, 60, 50, 50, 48],
"社会": [80, 88, 70, 62, 86, 70, 79, 65, 75, 67, 75, 68, 60]
}
df = pd.DataFrame(data)
df.head()
# 表が表示される
このデータを、散布図で表示するには、
「データフレーム.plot.scatter(x="横軸の列名", y="縦軸の列名", c="色")」と命令します。
●プログラム例(入力プログラム)
df.plot.scatter(x="数学", y="理科", c="b")
plt.title("数学と理科の関係性")
plt.show()
df.plot.scatter(x="数学", y="社会", c="b")
plt.title("数学と社会の関係性")
plt.show()
# 散布図が表示される
この結果を見ると、数学と理科は「数学の点が高いほど、理科の点も高くなっている」
ので関係性がありそうです。一方、数学と社会は「数学の点が高いほど、社会の点が高くなっているといえない」ようなので、関係性はあまりなさそうに見えます。
このように散布図は、「点のまとまり具合」を見ることで「関係性の強さ」がわかります。
このときの「傾き方」については、
「右肩上がり」の傾きは、「ある値が大きくなると、別の値も同じように大きくなる」ことを表していて「正の相関」といいます。
「右肩下がり」の傾きは、「ある値が大きくなると、別の値は逆に小さくなる」ことを表していて「負の相関」といいます。
●相関係数
この「関係性の強さと傾き」を「1つの数値」で表したものがあります。
それが「相関係数」です。
相関係数は「-1~+1」で表されます。+1に近ければ「強い正の相関」があり、-1に近ければ「強い負の相関」があり、0に近ければ「相関がない」ことを表します。
相関係数は「df.corr()["横の列名"]["縦の列名"]」で求めることができます。
◆データ分析の命令:列データの相関係数を求める
・ 必要なライブラリ:pandas
・ 命令
df.corr()["横の列名"]["縦の列名"]
・ 出力:列データの相関係数
例:「数学と理科」「数学と社会」の、2つの相関係数を表示してみる。
●プログラム例(入力プログラム)
print("数学と理科=", df.corr()["数学"]["理科"])
print("数学と社会=", df.corr()["数学"]["社会"])
# 数学と理科= 0.9688434503857298
# 数学と社会= 0.39425173157746296
「数学と理科には強い相関があり、数学と社会には相関はあまりなさそう」だとわかります。
「df.corr()」は、列名を指定しなければ、列の組み合わせを総当たりで調べて並べてくれます。
相関係数の行列なので、「相関行列」といいます。
◆データ分析の命令:相関行列を求める
・ 必要なライブラリ:pandas
・ 命令
df.corr()
・ 出力:データの相関行列
●プログラム例(入力プログラム)
print(df.corr())
# 数学 理科 社会
# 数学 1.000000 0.968843 0.394252
# 理科 0.968843 1.000000 0.413466
# 社会 0.394252 0.413466 1.000000
●散布図の上に線を引いて予想
データにはばらつきがありますが、誤差が最小になるように線を引くことができれば、「横軸のある値(説明変数)のとき、縦軸はどんな値(目的変数)になるか」を予測できます。
これを「回帰直線」といいます。
散布図の上に回帰直線を引くには、seabornの「sns.regplot()」という命令が使えます。
◆データ分析の命令:散布図+回帰直線を表示する
・ 必要なライブラリ:pandas、matplotlib、seaborn
・ 命令
sns.regplot(data=df, x="横軸", y="縦軸", line_kws={"color": "色"})
plt.show()
・ 出力:散布図の上に回帰直線
例:「数学と理科」「数学と社会」の、2つの散布図の上に回帰直線を表示してみる。
●プログラム例(入力プログラム)
sns.regplot(data=df, x="数学", y="理科", line_kws={"color":"red"})
plt.show()
sns.regplot(data=df, x="数学", y="社会", line_kws={"color":"red"})
plt.show()
# 散布図の上に回帰直線が表示される
相関が強ければはっきりした線が引けますが、相関が弱ければはっきりした線は引けません。薄い赤い範囲がそれを表していて、「95%の確率でこの範囲に入るだろう」という範囲です。
これを「信頼区間」といいます。
seabornには、散布図+回帰直線に、さらにヒストグラムを一緒に表示させる命令もあります。「sns.jointplot()」です。
◆データ分析の命令:ヒストグラム付き散布図+回帰直線を表示する
・ 必要なライブラリ:pandas、matplotlib、seaborn
・ 命令
sns.jointplot(data=df, x="横軸", y="縦軸", kind="reg", line_kws={"color": "色"})
plt.show()
・ 出力:ヒストグラム付き散布図+回帰直線
例:「数学と理科」「数学と社会」の、2つを表示してみる。
●プログラム例(入力プログラム)
sns.jointplot(data=df, x="数学", y="理科", kind="reg", line_kws={"color":"red"})
plt.show()
sns.jointplot(data=df, x="数学", y="社会", kind="reg", line_kws={"color":"red"})
plt.show()
# ヒストグラム付き散布図+回帰直線
総当たりで表示させる散布図
●相関行列を色の熱さで表現する:ヒートマップ
「熱そうな色ほど大きい値」と感覚的に見ることができます。
seabornの「sns.heatmap()」という命令で表示できます。
◆データ分析の命令:相関行列を色分けして表示する
・ 必要なライブラリ:pandas、matplotlib、seaborn
・ 命令
sns.heatmap(df.corr())
plt.show()
・ 出力:ヒートマップ
例:ヒートマップを表示してみる。相関係数の数値も一緒に表示させたいので「annot=True」と指定し、最大値を1、最小値を-1、中央の相関なしを0にして、
色分けしたいので、「vmax=1, vmin=-1, center=0」と指定します。
●プログラム例(入力プログラム)
sns.heatmap(df.corr(), annot=True, vmax=1, vmin=-1, center=0)
plt.show()
# ヒートマップ
斜めの部分は1なので一番明るい色になっていますが、その次に明るいのは「数学と理科」で、相関が強いことがわかります。
「数学と社会」「理科と社会」は暗く、相関が弱いと感覚的にわかります。
●総当たりで表示させる散布図:散布図行列
「散布図のすべての組み合わせを行列で表示させたもの」を
「散布図行列」といいます。seabornの「sns.pairplot(data=df)」という命令を使います。
◆データ分析の命令:散布図のすべての組み合わせを行列で表示させる
・ 必要なライブラリ:pandas、matplotlib、seaborn
・ 命令
sns.pairplot(data=df)
plt.show()
・ 出力:散布図行列
●プログラム例(入力プログラム)
sns.pairplot(data=df)
plt.show()
# 散布図行列
「相関行列」と同じように斜め部分は同じデータな同士なので
散布図の代わりにヒストグラムが表示されています。
さらにこの上に、回帰直線を表示させてみます。
オプションで「kind="reg"」と指定します。
●プログラム例(入力プログラム)
sns.pairplot(data=df, kind="reg")
plt.show()
# 散布図行列 + 回帰直線
アヤメのデータを見てみよう
アヤメの「がくの長さ」「がくの幅」「花びらの長さ」「花びらの幅」は品種と関係があるのではないか。(英)ロナルド・フィッシャー
※この論文データが機械学習の分類のサンプルデータとして使われている。
このデータには、「setosa(セトサ:ヒオウギアヤメ)」「versicolor(バージカラー)」「versinica(バージニカ)」という3種類のアヤメの品種データが入っていて、
それぞれの「がくの長さ(sepal length)」「がくの幅(sepal width)」「花びらの長さ(petal length)」「花びらの幅(petal width)」の測定値が入っています。
◆データ分析の命令:アヤメの品種データを読み込む
・ 必要なライブラリ:pandas、matplotlib、seaborn
・ 命令
sns.load_dataset("iris")
・ 出力:列データの平均値
例:アヤメの品種データを読み込んで表示させてみる
●プログラム例(入力プログラム)
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()
df = sns.load_dataset("iris")
df.head()
# アヤメの品種データの表示
例:「がくの長さ・幅」「花びらの長さ・幅」の、どの関係性が強いのか、相関係数行列を表示してみる。
●プログラム例(入力プログラム)
df.corr()
# 相関係数行列の表示
例:ヒートマップを表示してみる。
●プログラム例(入力プログラム)
sns.heatmap(df.corr(), annot=True, vmax=1, vmin=-1, center=0)
plt.show()
# ヒートマップの表示
例:散布図行列を表示してみる。
●プログラム例(入力プログラム)
sns.pairplot(data=df)
plt.show()
# 散布図行列の表示
表示結果から、何となく大小2つのかたまりに分かれていることはわかります。
このデータは「3つの品種」が入ったデータですが、その3つの品種が混じったまま調べているからです。
このデータを品種ごとに分けて調べてみます。
ある列データで使われているデータの種類を取り出すには、
「df["列名"].unique()」という命令が使えます。
●プログラム例(入力プログラム)
df["species"].unique()
# array(['setosa', 'versicolor', 'virginica'], dtype=object)
3つの名前が使われていました。
この品種をそれぞれ別々に調べてみます。
列データの中から、「ある条件に合うデータを抽出」するには、
「データフレーム = データフレーム[条件]」を使います。
例えば、「speciesの値が、setosaのものだけを抽出する」には、
「df[df["species"]=="setosa"]」と命令します。
例:それぞれのヒートマップを表示してみる。
●プログラム例(入力プログラム)
onespecies = "setosa"
one = df[df["species"] == onespecies]
sns.heatmap(one.corr(), annot=True, vmax=1, vmin=-1, center=0)
plt.title(onespecies, fontsize=18)
plt.show()
# setosaのヒートマップ
●プログラム例(入力プログラム)
onespecies = "versicolor"
one = df[df["species"] == onespecies]
sns.heatmap(one.corr(), annot=True, vmax=1, vmin=-1, center=0)
plt.title(onespecies, fontsize=18)
plt.show()
# versicolorのヒートマップ
●プログラム例(入力プログラム)
onespecies = "virginica"
one = df[df["species"] == onespecies]
sns.heatmap(one.corr(), annot=True, vmax=1, vmin=-1, center=0)
plt.title(onespecies, fontsize=18)
plt.show()
# virginicaのヒートマップ
例:setosaの散布図行列と回帰直線を表示してみる。
●プログラム例(入力プログラム)
onespecies = "setosa"
one = df[df["species"] == onespecies]
sns.pairplot(data=one, kind="reg")
plt.show()
# setosaの散布図行列と回帰直線を表示
結果から、「がくの長さ(sepal_length)」が長くなると、「がくの幅(sepal_width)も広くなる」という相関が強くて、それ以外の相関は弱そうだとわかります。
次に、品種で分類わけして表示してみます。
「ある列の値で分類わけして表示させる」には、「hue="列名"」というオプションを指定します。
●プログラム例(入力プログラム)
sns.pairplot(data=df, hue="species")
plt.show()
# 分類わけの結果表示
versicolor(オレンジ)とvirginica(緑)は近い位置にいて、
setosa(青)は少し離れた位置にいるようです。