LoginSignup
3
8

Python:データ分析基礎(pandas,matplotlib)

Posted at

はじめに

「Python2年生 データ分析のしくみ 体験してわかる! 会話でまなべる!」で学習したので
備忘録として記載しています。

データ分析とは

客観的な事実をもとにして、よりよい解決方法を見つけること。

統計学とは、大量のデータから傾向を見つけ出して、法則を発見するための技術。

データ分析で必要なのは、データから推測する力と、分析結果を使って説明できる力。

データ分析の手順(PPDAC)

①Problem(問題の把握)
②Plan(調査の計画)
③Data(データの収集)
④Analysis(データの分析)
⑤Conclusion(結論を考える)⇒①へ戻る

表データ

横方向・・・1行、レコード、ロウ(row)
縦方法・・・1列、カラム(columns)

データフレーム

データフレームとはpandasが用意するデータ形式で、Excelのように行と列で管理できる。

「データフレーム = pd.DataFrame(data)」のように指定する。

データフレームの作成

●行データからデータフレームを作る

行データからデータフレームを作る.py
data = [[1行目データ], [2行目データ], [3行目データ]]
データフレーム = pd.DataFrame(data)
データフレームに列名とインデックス名を設定する.py
データフレーム.columns = [列名のリスト]
データフレーム.index = [インデックス名のリスト]

※始めから列名とインデックス名を設定しておく場合は、下記を記載する。
col = [列名のリスト]
idx = [インデックス名のリスト]

データフレームに列名とインデックス名を設定する.py
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

●列データからデータフレームを作る

列データからデータフレームを作る.py
data = {"列名":[列データ], "列名":[列データ], "列名":[列データ]}
idx = [インデックス名のリスト]
データフレーム = pd.DataFrame(data, index=idx)
列データからデータフレームを作る.py
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形式」がある。

CSVファイル(UTF-8形式)を読み込む.py
DataFrame = pd.read_csv("ファイル名.csv")
CSVファイル(Shift-JIS形式)を読み込む.py
DataFrame = pd.read_csv("ファイル名.csv", encoding="Shift_JIS")

●0列目をインデックスを読み込む

CSVファイル(0列目をインデックス)を読み込む.py
DataFrame = pd.read_csv("ファイル名.csv", index_col=0)

●ヘッダーがない状態で読み込む

CSVファイル(ヘッダーがない)を読み込む.py
DataFrame = pd.read_csv("ファイル名.csv", header=None)

列(columns)、インデックスの確認

●列(columns)の確認

列(columns)の確認.py
df.columns

●インデックスの確認

インデックスの確認.py
df.index

●列(columns)、インデックスをリストに変換する

リスト変換.py
# 列名をリスト変換
list1 = [i for i in df.columns]
print(list1)

# インデックス名をリスト変換
list2 = [i for i in df.index]
print(list2)

●各列のデータ種類の確認

データ種類の確認.py
df.dtypes

●データ個数の確認

データ個数の確認.py
len(df)

列データや行データを取り出す

●列データを取り出す

列データを取り出す.py
df["列名"]
複数の列データを取り出す.py
df[["列名", "列名"]]

●行データを取り出す

行データを取り出す.py
df.iloc[行番号]
複数の行データを取り出す.py
df.iloc[行番号, 行番号]

●要素データを取り出す

要素データを取り出す.py
df.iloc[行番号]["列名"]

列データや行データを追加する

●空のデータフレームを作る

空のデータフレームを作る.py
データフレーム = pd.DataFrame()

●列データを追加する

列データを追加する.py
データフレーム["新列名"] = 列データ

●プログラム例

プログラム例.py
import pandas as pd

dfA = pd.read_csv("test.csv", index_col=0)

dfB = pd.DataFrame() # 空のデータフレームを作成
dfB["国語"] = dfA["国語"]  # dfAをdfBへ代入
dfB # dfBを表示

●行データを追加する

列データを追加する.py
データフレーム = データフレーム.append(列データ)

●プログラム例

プログラム例.py
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.

列データや行データを削除する

●列データを削除する

列データを削除する.py
データフレーム.drop("列名", axis=1)

●プログラム例

プログラム例.py
import pandas as pd

dfA = pd.read_csv("test.csv", index_col=0)
dfA = dfA.drop("国語", axis=1)
dfA

●行データを削除する

行データを削除する.py
データフレーム.drop("行名")

●プログラム例

プログラム例.py
import pandas as pd

dfA = pd.read_csv("test.csv", index_col=0)
dfA = dfA.drop(dfA.index[3])
dfA

条件でデータを抽出する

●列データから「ある条件に合うデータを抽出する」

条件に合うかどうか調べる.py
データフレーム["列名"] = 
データフレーム["列名"] > 
データフレーム["列名"] < 
条件でデータを抽出.py
データフレーム = データフレーム[条件]

●プログラム例

プログラム例.py
import pandas as pd

dfA = pd.read_csv("test.csv", index_col=0)
dfA["国語"] > 80 # 国語が80より大きいか、True、Falseで表示

●プログラム例(抽出)

プログラム例(抽出).py
import pandas as pd

dfA = pd.read_csv("test.csv", index_col=0)
dfB = dfA[dfA["国語"] > 80] # 国語が80より大きいか抽出し、dfBへ代入
dfB

●プログラム例(複数の条件で抽出)

プログラム例(複数の条件で抽出).py
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と表示)

プログラム例(NaNと表示).py
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

●欠損値の個数

欠損値の個数.py
データフレーム.isnull().sum()

●プログラム例

プログラム例.py
dfA.isnull().sum() # 列データから個数を数える

●欠損値がある行を削除
※値がある行も合わせて削除される場合がある

欠損値がある行を削除.py
データフレーム = データフレーム.dropna()

●プログラム例

プログラム例.py
dfB = dfA.dropna() # 欠損値がある行を削除し、dfBへ代入
dfB # dfBを表示

●欠損値がある行だけを削除

欠損値がある行を削除.py
データフレーム = データフレーム.dropna(subset=["列名"])

●プログラム例

プログラム例.py
dfB = dfA.dropna(subset=["国語"]) # 国語データで欠損値がある行のみを削除し、dfBへ代入
dfB # dfBを表示

●欠損値を平均値で埋める

欠損値を平均値で埋める.py
データフレーム = データフレーム.fillna(データフレーム.mean())

●プログラム例

プログラム例.py
dfB = dfA.fillna(dfA.mean())
dfB

●欠損値を1つ前の値で埋める

欠損値を平均値で埋める.py
データフレーム = データフレーム.fillna(method='ffill')

●プログラム例

プログラム例.py
dfB = dfA.fillna(method='ffill')
dfB

重複したデータを削除する

●プログラム例

プログラム例.py
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

●重複データの個数

重複データの個数.py
データフレーム.duplicated().value_counts()

●プログラム例

プログラム例.py
dfA.duplicated().value_counts()
# False    3
# True     2 ※重複するデータが2つある
# dtype: int64

●重複データの2つ目以降を削除する

重複データの2つ目以降を削除する.py
データフレーム.drop_duplicates()

●プログラム例

プログラム例.py
dfB = dfA.drop_duplicates()
dfB

文字列型のデータを数値に変換する

●プログラム例

プログラム例.py
import pandas as pd

# 列データからデータフレームを作成
data = {
    "A" : ["100", "300"],
    "B" : ["500", "1,500"]
}
dfA = pd.DataFrame(data)
dfA
プログラム例.py
dfA.dtypes # データの種類を調べる
# A    object
# B    object
# dtype: object

●文字列の列データを整数に変換する

文字列の列データを整数に変換する.py
データフレーム["列名"] = データフレーム["列名"].astype(int)

●プログラム例

プログラム例.py
dfA["A"] = dfA["A"].astype(int) # A列を整数へ変換
dfA.dtypes # データの種類を調べる
# A     int32
# B    object
# dtype: object

●カンマ付き文字列の列データのカンマを削除する

カンマ付き文字列の列データのカンマを削除する.py
データフレーム["列名"] = データフレーム["列名"].str.replace(",", "")

●プログラム例

プログラム例.py
dfA["B"] = dfA["B"].str.replace(",", "").astype(int) # カンマ付きのB列を整数に変換
dfA.dtypes # データの種類を調べる
# A    int32
# B    int32
# dtype: object

平均値を求める

代表値の一つに平均値があります。
平均値とは、凹凸のあるデータの、凹凸を平らに均した値のこと。

「平均値 = データの合計 / データの個数」

●プログラム例

プログラム例.py
import pandas as pd

# 列データからデータフレームを作成
data = {
    "A" : [82, 89, 93, 85, 76],
    "B" : [100, 62, 82, 70, 86]
}
df = pd.DataFrame(data)
df

●列データの平均値を求める

列データの平均値を求める.py
df["列名"].mean()

●プログラム例

プログラム例.py
# A、Bの平均値を求める
print("A =", df["A"].mean())
print("B =", df["B"].mean())
# A = 85.0
# B = 80.0

代表値は、「データの比較」に使う

このように求めた代表値は、「データの比較」に使います。
「代表値と、代表値を比較」すると「グループとグループの差」がわかります。

●各列データの平均値を求める

各列データの平均値を求める.py
df.mean()

●プログラム例

プログラム例.py
print(df.mean())
# A    85.0
# B    80.0
# dtype: float64

●プログラム例(代表値と、1つのデータを比較)

プログラム例(代表値と、1つのデータを比較).py
# 「A」の「0番目」と「A」の平均値を比較する
print(df.iloc[0]["A"])
print("A =", df["A"].mean())
# 82
# A = 85.0
# この結果から、「0番目」はAの平均値以下であることがわかる

代表値は「データの比較」に使う
・ 代表値と、別の代表値を比較:グループとグループの差がわかる
・ 昔の代表値と、今の代表値を比較:グループの変化がわかる
・ 代表値と、1つのデータを比較:1つのデータが全体のどのあたりなのかがわかる

平均値を代表としていいか調べる

平均値は、外れ値の影響を受けやすいという性質がある。
「平均値より外れ値の影響を受けにくい」代表値が必要となる場合もある。
それが、中央値最頻値です。

・ 中央値:データを順番に並べたとき、ちょうど真ん中に来る値

・ 最頻値:データの中で一番多く現れる(最頻)値

●プログラム例

プログラム例.py
import pandas as pd

# 列データからデータフレームを作成
data = {
    "予想価格" : [240, 250, 150, 240, 300, 5000]
}
df = pd.DataFrame(data)
df

●プログラム例(平均値を求める)

プログラム例(平均値を求める).py
print(df.mean())
# 予想価格    1030.0
# dtype: float64

●各列データの中央値を求める

各列データの中央値を求める.py
df.median()

●プログラム例(中央値を求める)

プログラム例(中央値を求める).py
print(df.median())
# 予想価格    245.0
# dtype: float64

●各列データの最頻値を求める

各列データの最頻値を求める.py
df.mode()

●プログラム例(最頻値を求める)

プログラム例(最頻値を求める).py
print(df.mode())
#    予想価格
# 0   240

平均値、中央値、最頻値の違い
平均値
・ すべてのデータを考慮した値
・ 外れ値の影響を受けやすい
・ 標準偏差との相性がいいのでよく使われる

中央値
・ データを順番に並べたとき、ちょうど真ん中に来る値
・ 外れ値の影響をあまり受けにくい

最頻値
・ データの中で一番多く現れる(最頻)値
・ 外れ値の影響をあまり受けにくい
・ サンプル数が少ないと使えない

データのばらつきを調べる

データのばらつき方を表にして調べるときは、度数分布表を使います。

・ 階級:たくさんのデータをいくつかの範囲で区切った際の、区切った範囲のこと。

・ 度数:区切った範囲内にデータがいくつ入っているか、個数のこと。

・ 度数分布表:度数を表にして、データの分布をわかるようにしたもの。度数分布表を見ると、「データはどこからどこまであって」「全体が均等にばらついているのか、どこかだけに集中しているのか」などがわかる。

●プログラム例

プログラム例.py
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

●プログラム例(平均値を求める)

プログラム例(平均値を求める).py
print(df.mean())
# A    5.5
# B    5.5
# C    5.5
# dtype: float64

●プログラム例(中央値を求める)

プログラム例(中央値を求める).py
print(df.median())
# A    5.5
# B    5.5
# C    5.5
# dtype: float64

●プログラム例(最頻値を求める)

プログラム例(最頻値を求める).py
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

●列データの度数分布表を表示する

列データの度数分布表を表示する.py
# pd.cut()でいくつかの範囲に区切る
cut = pd.cut(df["列名"], bins=区切る範囲, right=False)
# cut.value_counts()でそれぞれの範囲にいくつデータが入っているかカウントする
cut.value_counts(sort=False)

●プログラム例(Aの度数分布表を表示)

プログラム例(Aの度数分布表を表示).py
# 「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中に
グラフを表示させます。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
%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"])」と命令するだけで、日本語が使えるようになります。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
%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"(目盛りあり)などを指定できます。

データのばらつきがわかる:ヒストグラム

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
%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()
・ 出力:列データのばらつきがわかるヒストグラム

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
# 区切る範囲を指定
bins = [1,3,5,7,9,11]

df.plot.hist(bins=bins)
# タイトルを作成
plt.title("ケーキの感想はどのように違うか?")
plt.show()
# グラフが表示される

◎ヒストグラムは度数分布表をグラフ化したもの。
グラフを作る前に「何のためのグラフなのか」を意識して、グラフが表示されたら
「ここから何が読み取れるか」を考える。この積み重ねで、ただの客観的なデータが、
人間にとって意味のあるデータになってくる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
# 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()
# グラフが表示される

基本的なグラフを作る

大小を比較できる:棒グラフ

棒グラフは「数量の大小を比較できるグラフ」です。
「棒の高さ」がそれぞれの量を表しています。
「それぞれ独立した値を比較するとき」に使います。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
%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()
・ 出力:列データの棒グラフ

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
# 棒グラフで表示
df.plot.bar()
# タイトルを作成
plt.title("3名の成績")
plt.show()
# 棒ブラフが作成される

数値データの「国語」「数学」「英語」の列がグラフ化されました。ただし、
文字列データの「名前」の列はグラフ化できないので、自動的に表示対象から外されています。
グラフの横軸をみると、インデックス番号が表示されています。
「名前」の列を、インデックスに使う。「df.set_index("列名", inplace=True)」で指定します。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
# インデックスの置き換え
df.set_index("名前", inplace=True)
df
# 表が作成される

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
df.plot.bar()
plt.title("3名の成績")
plt.show()
# 棒ブラフの横軸が変更される

「df["列名"]」と指定すると、特定の列データのみだけでグラフを表示できます。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
df["国語"].plot.bar()
plt.title("国語の成績")
plt.show()
# 国語のみの棒ブラフが表示される

変化がわかる:折れ線グラフ

折れ線グラフは「時間的な値の変化がわかるグラフ」です。
時間で変化するデータに使うので、項目名が「年、月、日、時、分」になっているなど
「時系列に並んでいるデータ」に使います。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
%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
# 表が表示される

インデックスと月の数字がずれているので、「月」の列を、インデックスとして指定します。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
df.set_index("", inplace=True)
df.head()
# 表が表示される

このデータを折れ線グラフで表示してみます。
折れ線グラフにするには、「データフレーム.plot()」と命令します。

◆データ分析の命令:列データの折れ線グラフを表示する
・ 必要なライブラリ:pandas、matplotlib、(seaborn)
・ 命令
  df["列名"].plot()
  plt.show()
・ 出力:列データの折れ線グラフ

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
df.plot()
plt.title("日本の気温の変化")
plt.show()
# 折れ線グラフが表示される

「df["列名"]」と指定すると、特定の列データのみだけでグラフを表示できます。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
df["東京"].plot()
plt.title("東京の気温の変化")
plt.show()
# 東京の折れ線グラフが表示される

要素の割合を比較できる:円グラフ

円グラフは「全体に対する要素の割合がわかるグラフ」です。
「すべての要素の値を合計して100%になるデータ」に使います。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
%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()
・ 出力:列データの円グラフ

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
df["クッキー"].plot.pie()
plt.title("お菓子の好き嫌いは、どのような割合か?")
plt.show()
# 円グラフの表示

matplotlibの円グラフは、「右側から始まって反時計回り」に描かれます。
一般的な円グラフのように「真上から始まって時計回り」に描かれるように変更します。
オプションで「startangle=90,counterclock=False」と指定します。

文字を円グラフの内側に表示させるには、「labeldistance=0.5」を追加します。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
df["クッキー"].plot.pie(startangle=90, counterclock=False, labeldistance=0.5)
plt.title("お菓子の好き嫌いは、どのような割合か?")
plt.show()
# 円グラフの表示

棒グラフ・折れ線グラフ・円グラフの見分け方
データ->合計すると100%か?->円グラフ
   ->時系列に進んだデータか?->折れ線グラフ
   ->独立した値の比較か?->棒グラフ

ばらつきのわかるグラフ

データのばらつきを比較できる:箱ひげ図

箱ひげ図は「データのばらつきを比較できるグラフ」です。
複数のデータのばらつきを比較するときに使用します。

スクリーンショット 2023-07-19 132432.png

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
%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()
・ 出力:各列データの箱ひげ図

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
sns.boxplot(data=df, width=0.2)
plt.title("身長のばらつきに違いはあるか?")
plt.show()
# 箱ひげ図の表示

※出力結果から、「Aのほうがばらつきが大きく、Bのほうがまとまっている」、
「Aのほうが身長の高い生徒がいるが、中央値はBのほうが高い」とわかる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
print(df.median()) # 中央値を出力
# A    168.5
# B    168.9
# dtype: float64

2種類のデータの関係性がわかる:散布図

散布図は「2種類のデータの関係性がわかるグラフ」です。
「あるデータと別のデータに関係性があるかを目で見て確認するとき」に使います。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
%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()
・ 出力:指定した列データの散布図

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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つの点を追加する

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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)を追加する

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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種類のデータ」があります。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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)に水平線を引いておきます。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
%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()
・ 出力:各列データの分散

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
print(df.var())
# ID      9.166667
# A     430.666667
# B      12.888889
# dtype: float64

「2乗したのだから、平方根でもとの単位に戻す」⇒「標準偏差」
計算では、「分散の平方根」で求めます。
pandasでは、「データフレーム.std()」と命令します。

◆データ分析の命令:各列データの標準偏差を求める
・ 必要なライブラリ:pandas
・ 命令
  df.std()
・ 出力:各列データの標準偏差

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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の範囲を求めてみます。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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の範囲を求めてみます。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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)」と設定して、どちらも縦軸をそろえます。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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%の範囲を表す値」も横軸のどこかにあるはずです。

「平均値」「平均値ー標準偏差」「平均値+標準偏差」の位置に垂直線を引いてみます。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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%の範囲を示している」ことがわかります。

自然なばらつき

「正規分布」とは、「自然界でごく普通の、よくある分布」という意味。

●なぜ正規分布は、自然界でごく普通の分布か?

「平均値付近のことはよく起こり、平均値から遠いとめったに起こらなくなる」
「自然界のものは正規分布になることが多い」ということと「カーブ(ガウス分布)は、計算で求めることができる」
「自然界のばらつきとは、誤差の積み重ねでできているのではないか」=「中心極限定理」

●ゴルトンボードをシュミレート

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
%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は下から何%の位置にあるか」

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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」で求めてみる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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なのか」

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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」で求めてみる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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つの点が上から何%の珍しいことか」を比べることで、どちらがよりがんばったのかを調べることができます。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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(平均値, 標準偏差, 個数)」命令を使うと、「中央が一番多い、正規分布になるようなランダムな値」を作ることができます。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
%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が上から何%となるか調べてみる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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%に入るのに必要な偏差値を調べてみる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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が上から何%になるのか調べる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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の場合を調べる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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種類のデータに、どのくらい関係性があるか」を見ることができます。

例:「数学と理科と社会」の成績データで、「数学と理科」「数学と社会」の関係性はあるか調べる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
%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="色")」と命令します。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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に近ければ「相関がない」ことを表します。

スクリーンショット 2023-07-29 141630.png

相関係数は「df.corr()["横の列名"]["縦の列名"]」で求めることができます。

◆データ分析の命令:列データの相関係数を求める
・ 必要なライブラリ:pandas
・ 命令
  df.corr()["横の列名"]["縦の列名"]
・ 出力:列データの相関係数

例:「数学と理科」「数学と社会」の、2つの相関係数を表示してみる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
print("数学と理科=", df.corr()["数学"]["理科"])
print("数学と社会=", df.corr()["数学"]["社会"])
# 数学と理科= 0.9688434503857298
# 数学と社会= 0.39425173157746296

「数学と理科には強い相関があり、数学と社会には相関はあまりなさそう」だとわかります。

「df.corr()」は、列名を指定しなければ、列の組み合わせを総当たりで調べて並べてくれます。
相関係数の行列なので、「相関行列」といいます。

◆データ分析の命令:相関行列を求める
・ 必要なライブラリ:pandas
・ 命令
  df.corr()
・ 出力:データの相関行列

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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つの散布図の上に回帰直線を表示してみる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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つを表示してみる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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」と指定します。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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()
・ 出力:散布図行列

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
sns.pairplot(data=df)
plt.show()
# 散布図行列

「相関行列」と同じように斜め部分は同じデータな同士なので
散布図の代わりにヒストグラムが表示されています。

さらにこの上に、回帰直線を表示させてみます。
オプションで「kind="reg"」と指定します。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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")
・ 出力:列データの平均値

例:アヤメの品種データを読み込んで表示させてみる

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()

df = sns.load_dataset("iris")
df.head()
# アヤメの品種データの表示

例:「がくの長さ・幅」「花びらの長さ・幅」の、どの関係性が強いのか、相関係数行列を表示してみる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
df.corr()
# 相関係数行列の表示

例:ヒートマップを表示してみる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
sns.heatmap(df.corr(), annot=True, vmax=1, vmin=-1, center=0)
plt.show()
# ヒートマップの表示

例:散布図行列を表示してみる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
sns.pairplot(data=df)
plt.show()
# 散布図行列の表示

表示結果から、何となく大小2つのかたまりに分かれていることはわかります。
このデータは「3つの品種」が入ったデータですが、その3つの品種が混じったまま調べているからです。
このデータを品種ごとに分けて調べてみます。

ある列データで使われているデータの種類を取り出すには、
「df["列名"].unique()」という命令が使えます。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
df["species"].unique()
# array(['setosa', 'versicolor', 'virginica'], dtype=object)

3つの名前が使われていました。
この品種をそれぞれ別々に調べてみます。
列データの中から、「ある条件に合うデータを抽出」するには、
「データフレーム = データフレーム[条件]」を使います。
例えば、「speciesの値が、setosaのものだけを抽出する」には、
「df[df["species"]=="setosa"]」と命令します。

例:それぞれのヒートマップを表示してみる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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のヒートマップ

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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のヒートマップ

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
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の散布図行列と回帰直線を表示してみる。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
onespecies = "setosa"

one = df[df["species"] == onespecies]
sns.pairplot(data=one, kind="reg")
plt.show()
# setosaの散布図行列と回帰直線を表示

結果から、「がくの長さ(sepal_length)」が長くなると、「がくの幅(sepal_width)も広くなる」という相関が強くて、それ以外の相関は弱そうだとわかります。

次に、品種で分類わけして表示してみます。
「ある列の値で分類わけして表示させる」には、「hue="列名"」というオプションを指定します。

●プログラム例(入力プログラム)

プログラム例(入力プログラム).py
sns.pairplot(data=df, hue="species")
plt.show()
# 分類わけの結果表示

versicolor(オレンジ)とvirginica(緑)は近い位置にいて、
setosa(青)は少し離れた位置にいるようです。

終了

3
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
8