はじめに
データ分析関連の基礎を身に着けるため、本を読みながら勉強しています。
データを分析する際には便利そうなpandasについていろいろ試しながら確認したので、結果をまとめてみました。
基礎的な内容かもしれませんが、知らない事がたくさんあり、勉強になりました。
pandas のデータの形 seriesとdataframe
pandasには1次元のseriesと2次元のdataframeがあります。
a = pd.Series([10,20,30,40])
print(a)
b = pd.DataFrame([[10,"apple",True],
[30,"banana",False],
[20,"orange",True],
[40,"grape",False]]
)
print(b)
0 10
1 20
2 30
3 40
dtype: int64
0 1 2
0 10 apple True
1 30 banana False
2 20 orange True
3 40 grape False
表示方法 tail head
データフレームを表示させる際に先頭から表示させる場合にはheadを、末尾から表示させる場合はtailを使います。
df = pd.DataFrame([[10,"apple",True],
[30,"banana",False],
[20,"orange",True],
[40,"grape",False]]
)
a = df.tail(1)
b = df.head(1)
0 1 2
3 40 grape False
0 1 2
0 10 apple True
インデックス名(行)とカラム名(列) index columns
データフレームには行と列に名前を付けることができます。
行に名前を付ける場合にはindexを、列に名前を付ける場合にはcolumnsを使用します。
df = pd.DataFrame([[10,"apple",True],
[30,"banana",False],
[20,"orange",True],
[40,"grape",False]]
)
df.index = ["A","B","C","D"]
df.columns = ["番号","名前","真偽"]
print(df)
番号 名前 真偽
A 10 apple True
B 30 banana False
C 20 orange True
D 40 grape False
データの抽出 loc iloc
データフレームからデータを取り出す際には、locメソッドやilocメソッドを使います。
locメソッドを使うと、インデックス名とカラム名からデータを抽出することができ、
ilocメソッドを使うと、インデックス番号とカラム番号からデータを抽出することができます。
以下はそれぞれのメソッドを使って同じデータを参照している例です。
import numpy as np
import pandas as pd
df = pd.DataFrame(np.arange(12).reshape((4,3)),
columns=["A","B","C"],
index= ["1","2","3","4"])
print(df)
print(df.loc[:,"B"])
print(df.iloc[:,1])
print(df.loc["3","C"])
print(df.iloc[2,2])
A B C
1 0 1 2
2 3 4 5
3 6 7 8
4 9 10 11
1 1
2 4
3 7
4 10
Name: B, dtype: int32
1 1
2 4
3 7
4 10
Name: B, dtype: int32
8
8
データフレームの読み書き
データフレームを作成する場合、手入力ではなく、Excelファイル、CSVファイル、Webサイトから作成する場合には以下のように行います。
・webサイトから読み出す場合
wikiediaから宮城県の自治体の情報を取得してみました。
url = "https://ja.wikipedia.org/wiki/%E5%AE%AE%E5%9F%8E%E7%9C%8C"
tables = pd.read_html(url)
print(tables[4]) #見たいテーブルの位置に合わせる必要あり
地域圏 市区町村 団体コード 郡 2010年国調(人) 推計人口(人) 増減率(%)
0 気仙沼・本吉圏 気仙沼市 04205-6 市 73489 59179 -19.47
1 気仙沼・本吉圏 南三陸町 04606-0 本吉郡 17429 11876 -31.86
2 登米圏 登米市 04212-9 市 83969 74132 -11.72
3 栗原圏 栗原市 04213-7 市 74932 62609 -16.45
(省略)
38 仙南圏 蔵王町 04301-0 刈田郡 12882 11127 -13.62
39 仙南圏 七ヶ宿町 04302-8 刈田郡 1694 1201 -29.10
・エクセルを使う場合
以下のようにpd.read_excelを使ってデータフレームを変数に代入します。
df = pd.read_excel("XXXXXXXXX.xlsx")
加工したデータフレームをエクセルに保存する場合には、to_excelを使用します。
df.to_excel("XXXXXXXXX.xlsx")
・CSVを使う場合
以下のようにpd.read_csvを使ってデータフレームを変数に代入します。
df = pd.read_csv("XXXXXXXXXX.csv")
加工したデータフレームをCSVに保存する場合には、to_csvを使用します。
df.to_csv("XXXXXXXXXX.csv")
・pickleを使う場合
pythonのデータフレームを直列化して保存する形式として、pickle形式があります。
使い方はexcelやcsvと同じで、データフレームをファイルに出力したり読み込んだりすることができます。
ファイルから読み出す場合は以下のようにします。
df = pd.read_pickle("XXXXXXXXXX.pickle")
ファイルに出力する場合は以下に用にします。
df.to_pickle("XXXXXXXXXX.pickle")
データを条件付きで抽出
取得したデータフレームに対して、特定のカラムの要素をチェックして真偽を返したり、条件に一致しているデータだけを抽出するには以下のようにします。
url = "https://ja.wikipedia.org/wiki/%E5%AE%AE%E5%9F%8E%E7%9C%8C"
tables = pd.read_html(url)
df = tables[4]
population_growth = df["増減率(%)"] > 0
print(population_growth)
population_growth_town = df[df["増減率(%)"] > 0]
print(population_growth_town)
0 False
1 False
2 False
(省略)
38 False
39 False
Name: 増減率(%), dtype: bool
地域圏 市区町村 団体コード 郡 2010年国調(人) 推計人口(人) 増減率(%)
12 仙台都市圏 大衡村 04424-5 黒川郡 5334 5665 6.21
13 仙台都市圏 大和町 04421-1 黒川郡 24894 28651 15.09
15 仙台都市圏 富谷市 04216-1 市 47042 51542 9.57
18 仙台都市圏 利府町 04406-7 宮城郡 33994 35207 3.57
21 仙台都市圏 仙台市 04100-9 市 1045986 1093543 4.55
22 仙台都市圏 宮城野区 04102-5 行政区 190473 195568 2.67
23 仙台都市圏 若林区 04103-3 行政区 132306 141260 6.77
25 仙台都市圏 青葉区 04101-7 行政区 291436 310682 6.60
26 仙台都市圏 太白区 04104-1 行政区 220588 235634 6.82
27 仙台都市圏 名取市 04207-2 市 73134 78629 7.51
33 仙南圏 大河原町 04321-4 柴田郡 23530 23635 0.45
データの並び替え sort_values
先ほど取得した宮城県の自治体の情報の増減率を降順に並べ替えるにはsort_valuesを使います。
気まぐれでこのデータ使いましたが震災以降沿岸地域の人口が減ってる様子がわかります。
url = "https://ja.wikipedia.org/wiki/%E5%AE%AE%E5%9F%8E%E7%9C%8C"
tables = pd.read_html(url)
df = tables[4]
population_growth = df.sort_values(by="増減率(%)", ascending=False)
print(population_growth)
地域圏 市区町村 団体コード 郡 2010年国調(人) 推計人口(人) 増減率(%)
13 仙台都市圏 大和町 04421-1 黒川郡 24894 28651 15.09
15 仙台都市圏 富谷市 04216-1 市 47042 51542 9.57
27 仙台都市圏 名取市 04207-2 市 73134 78629 7.51
(省略)
39 仙南圏 七ヶ宿町 04302-8 刈田郡 1694 1201 -29.10
1 気仙沼・本吉圏 南三陸町 04606-0 本吉郡 17429 11876 -31.86
5 石巻圏 女川町 04581-1 牡鹿郡 10051 6200 -38.31
時系列データをまとめる pd.date_range groupby
2022年5月27日から始まる10日分の日付のデータをpd.date_rangeで作成します。
作成したデータに値のカラムを追加して、1~5の値をランダムに作成します。
作成したデータをgroupbyを使って月ごとの平均値を算出します。
dates = pd.date_range(start="2022-05-27",periods=10)
print(dates)
np.random.seed(100)
df = pd.DataFrame(np.random.randint(1,5,10),index=dates,columns=["値"])
print(df)
m_df = df.groupby(pd.Grouper(freq='M')).mean()
print(m_df)
DatetimeIndex(['2022-05-27', '2022-05-28', '2022-05-29', '2022-05-30',
'2022-05-31', '2022-06-01', '2022-06-02', '2022-06-03',
'2022-06-04', '2022-06-05'],
dtype='datetime64[ns]', freq='D')
値
2022-05-27 1
2022-05-28 1
2022-05-29 4
2022-05-30 4
2022-05-31 4
2022-06-01 4
2022-06-02 1
2022-06-03 3
2022-06-04 3
2022-06-05 1
値
2022-05-31 2.8
2022-06-30 2.4
ランダムな値に対して、月曜日の日付でグループ化して、週ごとの合計値(日曜から月曜まで)を出力する場合には以下のようにします。
import numpy as np
import pandas as pd
np.random.seed(123)
#2020-01-01から31日分の行に対して1~10の数字をランダムに割り当て
dates = pd.date_range(start="2020-01-01", periods=31)
df = pd.DataFrame(np.random.randint(1, 10, 31), index=dates, columns=["rand"])
print(df)
#月曜日の日付で週ごとの合計値を出力
df_year = pd.DataFrame(df.groupby(pd.Grouper(freq='W-MON')).sum(), columns=["rand"] )
print(df_year)
rand
2020-01-01 3
2020-01-02 3
2020-01-03 7
2020-01-04 2
2020-01-05 4
2020-01-06 7
2020-01-07 2
2020-01-08 1
2020-01-09 2
2020-01-10 1
2020-01-11 1
2020-01-12 4
2020-01-13 5
2020-01-14 1
2020-01-15 1
2020-01-16 5
2020-01-17 2
2020-01-18 8
2020-01-19 4
2020-01-20 3
2020-01-21 5
2020-01-22 8
2020-01-23 3
2020-01-24 5
2020-01-25 9
2020-01-26 1
2020-01-27 8
2020-01-28 4
2020-01-29 5
2020-01-30 7
2020-01-31 2
rand
2020-01-06 26
2020-01-13 16
2020-01-20 24
2020-01-27 39
2020-02-03 18
欠損値処置 dropna fillna
データフレームにしたとき、データが入っていないとNaNと表示されます。
このようなデータに対して欠損値処理を行うことでデータを扱いやすくすることができます。
欠損値の処理方法には以下があります。
処理方法 | メソッド |
---|---|
行の削除 | df.dropna() |
前方の値で補完 | df.fillna(method='ffill') |
後方の値で補完 | df.fillna(method='bfill') |
0などの任意の値で補完 | df.fillna(0) |
平均値で補完 | df.fillna(df.mean()) |
中央値で補完 | df.fillna(df.median) |
最頻値で補完 | df.fillna(df.mode().iloc[0,:]) |
欠損値か銅貨の判定 | df.isnull() |
df = pd.DataFrame(np.arange(12).reshape((4,3)),
columns=["A","B","C"],
index= ["1","2","3","4"])
df["B"]["2"] = np.nan
df["B"]["4"] = np.nan
print(df)
df_drop = df.dropna()
print(df_drop)
df_zero = df.fillna(0)
print(df_zero)
df_mean = df.fillna(df.mean())
print(df_mean)
A B C
1 0 1.0 2
2 3 NaN 5
3 6 7.0 8
4 9 NaN 11
A B C
1 0 1.0 2
3 6 7.0 8
A B C
1 0 1.0 2
2 3 0.0 5
3 6 7.0 8
4 9 0.0 11
A B C
1 0 1.0 2
2 3 4.0 5
3 6 7.0 8
4 9 4.0 11
データの連結 pd.concat
データフレームを連結するにはpd.concatを使います。
・列方向(カラム方向)に連結する場合には以下のように行います。
dates_a = pd.date_range(start="2022-05-27",periods=10)
np.random.seed(100)
df_a = pd.DataFrame(np.random.randint(1,5,10),index=dates_a,columns=["値1"])
df_b = pd.DataFrame(np.random.randint(1,5,10),index=dates_a,columns=["値2"])
df_merged = pd.concat([df_a,df_b],axis=1)
print(df_merged)
値1 値2
2022-05-27 1 3
2022-05-28 1 2
2022-05-29 4 3
2022-05-30 4 3
2022-05-31 4 3
2022-06-01 4 3
2022-06-02 1 2
2022-06-03 3 1
2022-06-04 3 1
2022-06-05 1 4
・行方向(インデックス方向)に連結する場合には以下のように行います。
5/27から3日分のデータと6/27から3日分のデータを連結しています。
dates_a = pd.date_range(start="2022-05-27",periods=3)
np.random.seed(100)
df_a = pd.DataFrame(np.random.randint(1,5,3),index=dates_a,columns=["値"])
dates_b = pd.date_range(start="2022-06-27",periods=3)
np.random.seed(101)
df_b = pd.DataFrame(np.random.randint(1,5,3),index=dates_b,columns=["値"])
df_merged = pd.concat([df_a,df_b],axis=0)
print(df_merged)
値
2022-05-27 1
2022-05-28 1
2022-05-29 4
2022-06-27 4
2022-06-28 4
2022-06-29 2
データフレームの統計量の取得 max min mode mean median std
データフレームのカラムを指定して、その要素の情報を取得します。
以下は値の内容を見て、最大値、最小値、最頻値、平均値、中央値、標準偏差を出力しています。
describeを使って統計情報を一括表示することもできます。
dates = pd.date_range(start="2022-05-27",periods=10)
np.random.seed(100)
df = pd.DataFrame(np.random.randint(1,5,10),index=dates,columns=["値"])
print(df)
print(df.max()) #最大値
print(df.min()) #最小値
print(df.mode()) #最頻値
print(df.mean()) #平均値
print(df.median()) #中央値
print(df.std()) #標準偏差
print(df.describe()) #統計量を一括表示
値 4
dtype: int32
値 1
dtype: int32
値
0 1
1 4
値 2.6
dtype: float64
値 3.0
dtype: float64
値 1.429841
dtype: float64
値
count 10.000000
mean 2.600000
std 1.429841
min 1.000000
25% 1.000000
50% 3.000000
75% 4.000000
max 4.000000
データフレームをNumPy配列に変換 values
データフレームの変数に格納した宮城県の市区町村のデータをndarray形式に変換して出力します。
NumPy配列に変換するとカラムやインデックスの情報がなくなります。
url = "https://ja.wikipedia.org/wiki/%E5%AE%AE%E5%9F%8E%E7%9C%8C"
tables = pd.read_html(url)
df = tables[4].loc[:,["市区町村","増減率(%)"]]
print(df)
nd = df.loc[:,["市区町村","増減率(%)"]].values
print(nd)
市区町村 増減率(%)
0 気仙沼市 -19.47
1 南三陸町 -31.86
2 登米市 -11.72
(中略)
37 白石市 -14.80
38 蔵王町 -13.62
39 七ヶ宿町 -29.10
[['気仙沼市' -19.47]
['南三陸町' -31.86]
['登米市' -11.72]
(中略)
['白石市' -14.8]
['蔵王町' -13.62]
['七ヶ宿町' -29.1]]