Pandasの応用を扱います。Pandasには、DataFrameに対して、データベースで言うところの連結や結合の操作をする機能が備えられています。連結というのはDataFrameどうしを、横(表の列)方向あるいは縦(表の行)方向に単純につなげる操作です。結合というのはDataFrameどうしを、特定のKey(カラムあるいは列の属性)に基づいてつなげる操作です。
横(表の列)方向に連結した例
「名前」をKeyにして結合した例
連結は、2つのDataFrameを、横(表の列)方向あるいは縦(表の行)方向に単純につなげます。DataFrameを連結する際、主にインデックスあるいはカラムが一致している場合と、インデックスあるいはカラムが一致していない場合とがあります。
連結には、pandas.concat()を使います。例えば、以下のようにすると、DataFrameのリストの先頭から順に縦方向に連結します。
pandas.concat("DataFrameのリスト", axis = 0)
オプション"axis = 0"は縦方向に連結し、"axis = 1"は横方向に連結します。縦(表の行)方向の連結なら、同じカラムどうしのデータが連結されます。横(表の列)方向の連結なら、同じインデックスどうしのデータが連結されます。注意点は、連結したとき、連結方向のインデックスあるいはカラムがそのまま連結されますから、インデックスあるいはカラムが重複する可能性があるということです。
以下のコードはDataFrame型の変数df1とdf2とを、縦(表の行)方向に連結してdf_con1に代入するのと、横(表の列)方向に連結してdf_con2に代入する操作を実行します。
In
import numpy as np
import pandas as pd
# DataFrameを乱数で作成(インデックスとカラムを指定)
def random_df(index, colummns, seed):
np.random.seed(seed)
df = pd.DataFrame()
for column in columns:
df[column] = np.random.choice(range(101, 201), len(index))
df.index = index
return df
# DataFrameを作成(インデックスとカラムが一致するように)
columns = ["Tokyo", "Chiba", "Kanagawa", "Saitama"]
df1 = random_df(range(1, 10), columns, 1)
df2 = random_df(range(1, 10), columns, 2)
# df1とdf2とを、縦(表の行)方向に連結
df_con1 = pd.concat([df1, df2], axis = 0)
print(df_con1)
# df1とdf2とを、縦(表の行)方向に連結
df_con2 = pd.concat([df1, df2], axis = 1)
print(df_con2)
Out
Tokyo Chiba Kanagawa Saitama
1 138 102 112 197
2 113 177 129 187
3 173 172 130 114
4 110 107 115 110
5 176 126 151 108
6 106 151 169 164
7 180 121 188 162
8 165 119 188 123
9 117 185 195 158
1 141 150 138 168
2 116 196 140 170
3 173 176 168 189
4 123 186 105 169
5 144 148 143 147
6 183 164 152 171
7 176 132 139 196
8 108 191 134 184
9 135 121 159 132
Tokyo Chiba Kanagawa Saitama Tokyo Chiba Kanagawa Saitama
1 138 102 112 197 141 150 138 168
2 113 177 129 187 116 196 140 170
3 173 172 130 114 173 176 168 189
4 110 107 115 110 123 186 105 169
5 176 126 151 108 144 148 143 147
6 106 151 169 164 183 164 152 171
7 180 121 188 162 176 132 139 196
8 165 119 188 123 108 191 134 184
9 117 185 195 158 135 121 159 132
DataFrameのインデックスとカラムが一致していないとき、連結すると、インデックスやカラムに共通しない行や列が含まれます。そうした行や列のセルには"NaN"が入ります。
連結はDataFrameどうしをそのままつなげるので、ラベルに重複が生じることがあります。上記の連結の例だと、"Tokyo", "Chiba", "Kanagawa","Saitama"がラベルとして重複しています。このとき、pandas.concat()にkeysで指定したラベルを追加すると、multi-indexとなります。複数のラベルが付与された状態になり、一応、ラベルの重複は避けることができます。
以下の連結では、新たにラベル"A", "B"がカラムとして追加されています。この追加されたカラムは、既存のカラムの上位という位置づけになります。このとき、ラベル"A"がついているカラムを参照するには、df["A"]とします。さらに、ラベル"A"のカラムの中のラベル"Chiba"のカラムを参照するのは、df["A", "Chiba"]とします。
In
df_con3 = pd.concat([df1, df2], axis = 1, keys = ["A", "B"])
print(df_con3)
print(df_con3["A"])
print(df_con3["A", "Chiba"])
Out
A B
Tokyo Chiba Kanagawa Saitama Tokyo Chiba Kanagawa Saitama
1 138 102 112 197 141 150 138 168
2 113 177 129 187 116 196 140 170
3 173 172 130 114 173 176 168 189
4 110 107 115 110 123 186 105 169
5 176 126 151 108 144 148 143 147
6 106 151 169 164 183 164 152 171
7 180 121 188 162 176 132 139 196
8 165 119 188 123 108 191 134 184
9 117 185 195 158 135 121 159 132
Tokyo Chiba Kanagawa Saitama
1 138 102 112 197
2 113 177 129 187
3 173 172 130 114
4 110 107 115 110
5 176 126 151 108
6 106 151 169 164
7 180 121 188 162
8 165 119 188 123
9 117 185 195 158
1 102
2 177
3 172
4 107
5 126
6 151
7 121
8 119
9 185
Name: (A, Chiba), dtype: int32
結合は、マージとも言います。結合はKeyになっている列を指定し、2つのデータベースのKey内の値が一致する行を横につなげる処理です。結合には「内部結合」と「外部結合」とがあります。
「内部結合」では、Keyの列に共通の値が存在しない行は削除されます。つまり、両DataFrameのKeyとなるカラムのデータのうち、共通の行が残るということです。
「外部結合」では、Keyの列に共通の値が存在しない行も残ります。共通でない列にはデータがないので、NaNが入ります。
2つのDataFrameのdf1及びdf2に対して内部結合します。関数mergeを使い、その引数を以下のように指定します。
pandas.merge(df1, df2, on = "Keyとなるカラム", how = "inner")
この場合、df1が左側にきて、Keyの列で値が一致しない行は削除されます。Keyの列でなければ、列は残され、左側のDataFrameに属していたカラムには_xがつけられ、右側のDataFrameに属していたカラムには_yがつけられます。
In
import numpy as np
import pandas as pd
data1 = {"city" : ["Tokyo", "Chiba", "Kanagawa", "Saitama", "Tochigi"],
"year" : [2020, 2021, 2022, 2023, 2024],
"area" : [2194, 5158, 2416, 3798, 6408]}
df1 = pd.DataFrame(data1)
data2 = {"city" : ["Tokyo", "Chiba", "Kanagawa", "Saitama", "Gunma"],
"year" : [2020, 2021, 2022, 2023, 2025],
"area" : [2194, 5158, 2416, 3798, 6362]}
df2 = pd.DataFrame(data2)
print(df1)
print(df2)
# df1とdf2とを内部結合する
df_mer1 = pd.merge(df1, df2, on = "city", how = "inner")
print(df_mer1)
Out
city year area
0 Tokyo 2020 2194
1 Chiba 2021 5158
2 Kanagawa 2022 2416
3 Saitama 2023 3798
4 Tochigi 2024 6408
city year area
0 Tokyo 2020 2194
1 Chiba 2021 5158
2 Kanagawa 2022 2416
3 Saitama 2023 3798
4 Gunma 2025 6362
city year_x area_x year_y area_y
0 Tokyo 2020 2194 2020 2194
1 Chiba 2021 5158 2021 5158
2 Kanagawa 2022 2416 2022 2416
3 Saitama 2023 3798 2023 3798
2つのDataFrameのdf1及びdf2に対して外部結合します。関数mergeを使い、その引数を以下のように指定します。
pandas.merge(df1, df2, on = "Keyとなるカラム", how = "outer")
この場合、df1が左側にきて、Keyの列で値が一致しない行も残され、値がないところはNaNが入ります。Keyの列でない列も残され、左側のDataFrameに属していたカラムには_xがつけられ、右側のDataFrameに属していたカラムには_yがつけられます。
In
import numpy as np
import pandas as pd
data1 = {"city" : ["Tokyo", "Chiba", "Kanagawa", "Saitama", "Tochigi"],
"year" : [2020, 2021, 2022, 2023, 2024],
"area" : [2194, 5158, 2416, 3798, 6408]}
df1 = pd.DataFrame(data1)
data2 = {"city" : ["Tokyo", "Chiba", "Kanagawa", "Saitama", "Gunma"],
"year" : [2020, 2021, 2022, 2023, 2025],
"area" : [2194, 5158, 2416, 3798, 6362]}
df2 = pd.DataFrame(data2)
print(df1)
print(df2)
# df1とdf2とを外部結合する
df_mer1 = pd.merge(df1, df2, on = "city", how = "outer")
print(df_mer1)
Out
city year area
0 Tokyo 2020 2194
1 Chiba 2021 5158
2 Kanagawa 2022 2416
3 Saitama 2023 3798
4 Tochigi 2024 6408
city year area
0 Tokyo 2020 2194
1 Chiba 2021 5158
2 Kanagawa 2022 2416
3 Saitama 2023 3798
4 Gunma 2025 6362
city year_x area_x year_y area_y
0 Tokyo 2020.0 2194.0 2020.0 2194.0
1 Chiba 2021.0 5158.0 2021.0 5158.0
2 Kanagawa 2022.0 2416.0 2022.0 2416.0
3 Saitama 2023.0 3798.0 2023.0 3798.0
4 Tochigi 2024.0 6408.0 NaN NaN
5 Gunma NaN NaN 2025.0 6362.0
列名が同じでないDataFrameどうしを結合したい場合があります。これは、両DataFrameに各行を特定するIDが付けられているのですが、その列の名前が違っているのです。例えば、イベント情報ではイベントが開催される県の名前(場所)を示すカラムを"location"としているのに対して、県情報では県の名前を示すカラムを"prefecture"としているとします。
県の名前(場所)をKeyとしてイベント情報に県情報のデータを結合したいのですが、対応する列どうしのカラムが一致していません。このような場合、以下のようにそれぞれのカラムを指定して結合します。
pandas.merge(左側DF, 右側DF, left_on = "左側DFのカラム", right_on = "右側のDFのカラム", how = "結合方法")
In
import pandas as pd
df1 = pd.DataFrame(
[["Tokyo", 2020],
["Chiba", 2021],
["Kanagawa", 2022],
["Saitama", 2023],
["Tochigi", 2024]],
columns = ["location", "year"])
df2 = pd.DataFrame(
[["Tokyo", 2194],
["Chiba", 5158],
["Kanagawa", 2416],
["Saitama", 3798],
["Tochigi", 6462]],
columns = ["prefecture", "area"])
print(df1)
print(df2)
# df1とdf2とを内部結合する
df_mer1 = pd.merge(df1, df2, left_on = "location", right_on = "prefecture", how = "inner")
print(df_mer1)
Out
location year
0 Tokyo 2020
1 Chiba 2021
2 Kanagawa 2022
3 Saitama 2023
4 Tochigi 2024
prefecture area
0 Tokyo 2194
1 Chiba 5158
2 Kanagawa 2416
3 Saitama 3798
4 Gunma 6362
location year prefecture area
0 Tokyo 2020 Tokyo 2194
1 Chiba 2021 Chiba 5158
2 Kanagawa 2022 Kanagawa 2416
3 Saitama 2023 Saitama 3798
DataFrameの結合に用いられるKeyがインデックスになっている場合、left_on, right_onでカラムを指定するのではなく、left_index, right_indexに"True"を指定します。県の名前(場所)と県情報とを結合するとします。場所のIDで県情報のインデックスを参照し、内部結合するなら、以下のように指定します。
pandas.merge(県の名前(場所)のデータフレーム, 県情報のデータフレーム, left_on = "location", right_index = True, how = "innrer")
In
import pandas as pd
df1 = pd.DataFrame(
[["Tokyo", 2020],
["Chiba", 2021],
["Kanagawa", 2022],
["Saitama", 2023],
["Tochigi", 2024]],
columns = ["location", "year"])
df2 = pd.DataFrame(
[[2194],
[5158],
[2416],
[3798],
[6462]],
columns = ["area"])
df2.index = ["Tokyo", "Chiba", "Kanagawa", "Saitama", "Tochigi"]
print(df1)
print(df2)
# df1とdf2とを内部結合する
df_mer1 = pd.merge(df1, df2, left_on = "location", right_index = True, how = "inner")
print(df_mer1)
Out
location year
0 Tokyo 2020
1 Chiba 2021
2 Kanagawa 2022
3 Saitama 2023
4 Tochigi 2024
area
Tokyo 2194
Chiba 5158
Kanagawa 2416
Saitama 3798
Tochigi 6462
location year area
0 Tokyo 2020 2194
1 Chiba 2021 5158
2 Kanagawa 2022 2416
3 Saitama 2023 3798
4 Tochigi 2024 6462
データの量が多いとき、その特定の行だけ取り出したいことがあります。例えば、冒頭の5行だけ表示して確認したい、といったことがあるかも知れません。あるいは、末尾の5行だけ表示して確認したいということもあるでしょう。このようなとき、DataFrame型の変数に対して冒頭ならhead()メソッドを、末尾ならtail()メソッドを適用します。
引数に整数値を指定すると、指定した行数分を取り出します。引数を指定しなければ、5行分を取り出します。
In
import pandas as pd
import numpy as np
# np.random.seed(0)
columns = ["Tokyo", "Chiba", "Kanagawa", "Saitama", "Tochigi"]
# DataFrameを作り、列を追加する
df1 = pd.DataFrame()
for column in columns:
df1[column] = np.random.choice(range(1, 11), 10)
df1.index = range(1,11)
print(df1.head())
print(df1.head(3)) # 冒頭3行だけ表示
print(df1.tail())
print(df1.tail(3)) # 末尾3行だけ表示
Out
Tokyo Chiba Kanagawa Saitama Tochigi
1 4 4 5 10 1
2 4 5 9 7 3
3 4 2 10 8 10
4 6 1 9 6 2
5 1 9 9 10 5
Tokyo Chiba Kanagawa Saitama Tochigi
1 4 4 5 10 1
2 4 5 9 7 3
3 4 2 10 8 10
Tokyo Chiba Kanagawa Saitama Tochigi
6 3 6 5 2 4
7 10 7 9 1 6
8 8 9 1 9 10
9 4 3 8 1 6
10 8 9 4 7 8
Tokyo Chiba Kanagawa Saitama Tochigi
8 8 9 1 9 10
9 4 3 8 1 6
10 8 9 4 7 8
ライブラリNumPyの関数に、このPandasのSeriesやDataFrameの変数を渡すと、要素すべてに対して計算処理が適用されます。注意点は、NumPyの配列を受け取る関数に、DataFrameの変数を渡すと、「列単位」でまとめて計算処理が行われます。また、Pandasの変数どうし、あるいはPandasの変数と整数どうしの間で四則演算が可能です。
In
import pandas as pd
import numpy as np
columns = ["Tokyo", "Chiba", "Kanagawa", "Saitama", "Tochigi"]
# DataFrameを作り、列を追加する
df1 = pd.DataFrame()
for column in columns:
df1[column] = np.random.choice(range(1, 11), 10)
df1.index = range(1,11)
print(df1)
# df1の各要素を2倍し、df2に代入する
df2 = df1 + df1
print(df2)
# df1の各要素を2乗し、df3に代入する
df3 = df1 * df1
print(df3)
# df1の各要素の平方根を計算し、df4に代入する
df4 = np.sqrt(df1)
print(df4)
Out
Tokyo Chiba Kanagawa Saitama Tochigi
1 4 5 10 9 3
2 9 3 7 10 2
3 1 4 8 8 5
4 3 1 10 1 4
5 5 3 6 4 2
6 9 2 10 4 5
7 10 4 1 2 5
8 7 6 10 1 9
9 1 5 10 9 5
10 7 5 5 9 10
Tokyo Chiba Kanagawa Saitama Tochigi
1 8 10 20 18 6
2 18 6 14 20 4
3 2 8 16 16 10
4 6 2 20 2 8
5 10 6 12 8 4
6 18 4 20 8 10
7 20 8 2 4 10
8 14 12 20 2 18
9 2 10 20 18 10
10 14 10 10 18 20
Tokyo Chiba Kanagawa Saitama Tochigi
1 16 25 100 81 9
2 81 9 49 100 4
3 1 16 64 64 25
4 9 1 100 1 16
5 25 9 36 16 4
6 81 4 100 16 25
7 100 16 1 4 25
8 49 36 100 1 81
9 1 25 100 81 25
10 49 25 25 81 100
Tokyo Chiba Kanagawa Saitama Tochigi
1 2.000000 2.236068 3.162278 3.000000 1.732051
2 3.000000 1.732051 2.645751 3.162278 1.414214
3 1.000000 2.000000 2.828427 2.828427 2.236068
4 1.732051 1.000000 3.162278 1.000000 2.000000
5 2.236068 1.732051 2.449490 2.000000 1.414214
6 3.000000 1.414214 3.162278 2.000000 2.236068
7 3.162278 2.000000 1.000000 1.414214 2.236068
8 2.645751 2.449490 3.162278 1.000000 3.000000
9 1.000000 2.236068 3.162278 3.000000 2.236068
10 2.645751 2.236068 2.236068 3.000000 3.162278
Pandasでは、列ごとに平均、最大、最小などの要約統計量を計算するのも簡単です。DataFrame型の変数に対してdescibe()メソッドを適用すると、列ごとの個数、平均、標準偏差、最小、四分位、最大の値を、DataFrameとして返します。DataFrameのインデックスは要約統計量の名前です。
describe()メソッドは、列ごとの個数、平均、標準偏差、最小、四分位、最大の値のDataFrameを返します。df1のインデックス参照はdf.loc["インデックスのリスト"]で行います。
In
import pandas as pd
import numpy as np
columns = ["Tokyo", "Chiba", "Kanagawa", "Saitama", "Tochigi"]
# DataFrameを作り、列を追加する
df1 = pd.DataFrame()
for column in columns:
df1[column] = np.random.choice(range(1, 11), 10)
df1.index = range(1,11)
print(df1)
df1_desc = df1.describe().loc[["mean", "max", "min"]]
print(df1_desc)
Out
Tokyo Chiba Kanagawa Saitama Tochigi
1 9 2 5 6 5
2 2 6 9 7 3
3 3 6 7 2 1
4 3 8 10 3 6
5 9 2 4 6 8
6 9 1 10 9 8
7 2 5 1 4 3
8 6 10 3 5 5
9 2 4 6 10 9
10 6 6 8 5 4
Tokyo Chiba Kanagawa Saitama Tochigi
mean 5.1 5.0 6.3 5.7 5.2
max 9.0 10.0 10.0 10.0 9.0
min 2.0 1.0 1.0 2.0 1.0
Pandasで特に時系列分析に用いられる機能として、行(列)の間の差分を求める処理があります。DataFrame型の変数dfに対してdiff()メソッドを適用します。diff()メソッドの引数を以下のように指定すると、行間あるいは列間の差分を計算し、DataFrameとして返します。
df.diff("行あるいは列の間隔", axis = "方向")
第1引数が正のとき、前の行(列)との差分になり、負のとき、後の行(列)との差分になります。axisが"0"なら行の方向、"1"なら列の方向に処理されます。NaNは値が存在しないことを意味します。
In
import pandas as pd
import numpy as np
columns = ["Tokyo", "Chiba", "Kanagawa", "Saitama", "Tochigi"]
# DataFrameを作り、列を追加する
df1 = pd.DataFrame()
for column in columns:
df1[column] = np.random.choice(range(1, 11), 10)
df1.index = range(1,11)
print(df1)
df1_diff1 = df1.diff(2, axis = 0)
print(df1_diff1)
df1_diff2 = df1.diff(-1, axis = 1)
print(df1_diff2)
Out
Tokyo Chiba Kanagawa Saitama Tochigi
1 9 6 1 8 3
2 4 10 8 3 4
3 9 7 8 8 8
4 5 4 9 9 10
5 9 5 5 6 7
6 7 10 2 2 6
7 3 3 6 4 1
8 5 3 9 5 10
9 8 5 3 4 3
10 2 8 8 10 4
Tokyo Chiba Kanagawa Saitama Tochigi
1 NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN
3 0.0 1.0 7.0 0.0 5.0
4 1.0 -6.0 1.0 6.0 6.0
5 0.0 -2.0 -3.0 -2.0 -1.0
6 2.0 6.0 -7.0 -7.0 -4.0
7 -6.0 -2.0 1.0 -2.0 -6.0
8 -2.0 -7.0 7.0 3.0 4.0
9 5.0 2.0 -3.0 0.0 2.0
10 -3.0 5.0 -1.0 5.0 -6.0
Tokyo Chiba Kanagawa Saitama Tochigi
1 3.0 5.0 -7.0 5.0 NaN
2 -6.0 2.0 5.0 -1.0 NaN
3 2.0 -1.0 0.0 0.0 NaN
4 1.0 -5.0 0.0 -1.0 NaN
5 4.0 0.0 -1.0 -1.0 NaN
6 -3.0 8.0 0.0 -4.0 NaN
7 0.0 -3.0 2.0 3.0 NaN
8 2.0 -6.0 4.0 -5.0 NaN
9 3.0 2.0 -1.0 1.0 NaN
10 -6.0 0.0 -2.0 6.0 NaN
DataFrameに対して、特定の列(カラム)で同じ値の行があったとき、グループとしてまとめたいときがあります。この操作はグループ化といいます。DataFrameD型の変数に対してgroupby("カラム")メソッドを適用すると、指定したカラムの列に対してグループ化します。
このとき返されるのはGroupByオブジェクトですが、このグループ化の結果を直接表示することはできません。GroupByオブジェクトに対して関数mean()でグループの平均を求めた結果や、関数sum()でグループの和を求めた結果を表示します。
In
# グループ化
import pandas as pd
# データフレームの作成
data = {"city" : ["Tokyo", "Chiba", "Kanagawa", "Saitama", "Tochigi"],
"year" : [2020, 2021, 2022, 2023, 2024],
"area" : [2194, 5158, 2416, 3798, 6408],
"region":["center","south","south","north","north"]}
df = pd.DataFrame(data)
print(df)
# 直接表示できない
df_region = df.groupby("region")
print(df_region)
# グループ化した結果の平均値を求める
df_region_mean = df_region.mean()
print(df_region_mean)
Out
city year area region
0 Tokyo 2020 2194 center
1 Chiba 2021 5158 south
2 Kanagawa 2022 2416 south
3 Saitama 2023 3798 north
4 Tochigi 2024 6408 north
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000002DF28582190>
year area
region
center 2020.0 2194.0
north 2023.5 5103.0
south 2021.5 3787.0