Python - pandas
公開日:2019-06-22 更新日:2019-06-22
[Python]
1. 概要
pandas の使い方についてです。
pandas は、データ操作を行うためのモジュールです。
例えば、CSVを読み込んで、2次元のデータを必要な形式に加工したり、集計することが簡単に行えます。
データを、機械学習で使いやすいように、整える際にも使用されます。
pandas は、データ操作を行うためのモジュールです。
例えば、CSVを読み込んで、2次元のデータを必要な形式に加工したり、集計することが簡単に行えます。
データを、機械学習で使いやすいように、整える際にも使用されます。
2. データ
pandas では、
1次元のデータを Series
2次元のデータを DataFrame
3次元のデータを Panel
で保持します。
1次元のデータを Series
2次元のデータを DataFrame
3次元のデータを Panel
で保持します。
3. Series
1次元のデータを保持するクラスです。
DataFrame に対して、行・列の設定・取得をする際に Series を使います。
DataFrame に対して、行・列の設定・取得をする際に Series を使います。
3-1. 生成・値の設定・値の取得
import pandas as pd
# 生成
s = pd.Series(['Apple', 'Red', 500])
# 取得
print(s[0]) # Apple
print(s[1]) # Red
print(s[2]) # 500
print(s.count()) # 要素数:3
# 設定
s[0] = 'Orange'
print(s[0]) # Orange
3-2. インデックス(キー)の設定
インデックス(キー)を指定すると、辞書(連想配列)と同じように文字列で要素を参照できます。
s = pd.Series(
['Apple', 'Red', 500],
index = ['name', 'color', 'price']
)
print(s['name']) # Apple
print(s['color']) # Red
s['price'] = 700
print(s['price']) # 700
3-3. 値の取得 その2
at、iat で1つの値、loc、iloc で複数の値を取得できます。
先頭に i が付く方は [ ] に数値のインデックスを指定して、
i が付かない方には、文字列のキーを指定します。
iloc、loc は、1つの値も取得できますが、スライスを使って、複数の値を持った Series を取得できます。
先頭に i が付く方は [ ] に数値のインデックスを指定して、
i が付かない方には、文字列のキーを指定します。
iloc、loc は、1つの値も取得できますが、スライスを使って、複数の値を持った Series を取得できます。
s = pd.Series(['Apple', 'Red', 500], index = ['name', 'color', 'price'])
print(s.iat[1]) # Red
print(s.at['color']) # Red
print(s.iloc[1]) # Red
print(s.loc['color']) # Red
s2 = s.iloc[0:2] # または s.loc['name':'color']
print(s2[0]) # Apple
print(s2[1]) # Red
print(s2['name']) # Apple
print(s2['color']) # Red
3-4. データの追加
未使用のインデックスを指定して代入すると追加されます。
append() で 他の Series を追加することもできます。
False にすると、追加した要素だけインデックスが 0 から振られます。
既存のインデックスと重複してもエラーにならないため要注意。
s = pd.Series(['Apple', 'Red', 500])
s[3] = 'abc'
s[999] = '123'
s['key'] = 'test'
print(s)
# 0 Apple
# 1 Red
# 2 500
# 3 abc
# 999 123
# key test
append() で 他の Series を追加することもできます。
s = pd.Series(['Apple', 'Red', 500])
s = s.append(pd.Series([1, 2, 3]), ignore_index = True)
print(s)
# 0 Apple
# 1 Red
# 2 500
# 3 1
# 4 2
# 5 3
ignore_index を True にすると、全てのインデックスが 0 から振り直されます。False にすると、追加した要素だけインデックスが 0 から振られます。
既存のインデックスと重複してもエラーにならないため要注意。
3-5. データの削除
drop() で削除すると、要素が削除された新しい Series が返ります。
削除してもインデックスは変わりません。
inplace = True にすると、メソッドを実行した Series 自体から要素が削除されます。
削除してもインデックスは変わりません。
s = pd.Series(['Apple', 'Red', 500])
s = s.drop(0)
print(s)
# 1 Red
# 2 500
inplace = True にすると、メソッドを実行した Series 自体から要素が削除されます。
s.drop(0, inplace = True)
3-6. その他
最大、最小、平均
絞り込み
重複の削除
ソート
各要素にラムダ式を適用する
この他にも様々なメソッドが用意されています。
s = pd.Series([1,2,3,4,5])
print(s.max()) # 5
print(s.min()) # 1
print(s.mean()) # 3
絞り込み
s = pd.Series([1,2,3,4,5,6,7,8,9,10])
s = s[ s >= 5 ]
print(s) # 5 6 7 8 9 10
重複の削除
s = pd.Series([1,1,1,1,1, 2,2,2,2,2, 3,4,5])
s.drop_duplicates(inplace = True)
print(s) # 1 2 3 4 5
ソート
s = pd.Series([5, 1, 3, 2, 4])
s.sort_values(inplace = True)
print(s) # 1 2 3 4 5
各要素にラムダ式を適用する
s = pd.Series([1,2,3,4,5])
s = s.apply(lambda v : v ** 2)
print(s) # 1 4 9 16 25
この他にも様々なメソッドが用意されています。
4. DataFrame
4-1. 生成
index は行、columns は列(ラベル)に指定する名前で、要素にアクセスする際に使用します。
省略すると 0 から連番が振られます。
実行結果
省略すると 0 から連番が振られます。
import pandas as pd
df = pd.DataFrame(
[
['太郎', 5, 4, 4, 3],
['花子', 4, 5, 5, 4],
['次郎', 1, 2, 1, 2],
],
index = ['no1', 'no2', 'no3'],
columns = ['名前', '国語', '算数', '理科', '社会']
)
print(df)
実行結果
名前 国語 算数 理科 社会
no1 太郎 5 4 4 3
no2 花子 4 5 5 4
no3 次郎 1 2 1 2
4-2. 値の取得と設定
iloc はインデックス、loc は名前を指定して、要素に参照できます。
どちらも [行, 列] の順番になります。
また、df[列名] で列を特定して、そこから行のインデックス、または名前を指定して、要素を参照することができます。
取得
設定
また、以下のようにして設定しようとすると、警告が出ます。
これは、列(Series)を取得してから、列の要素を設定することになりますが、
元の DataFrame に反映されるためです。
上記警告は以下により消せますが、loc か iloc を使った方法に書き直した方が良いかもしれません。
参考:警告の制御
以下のように列をコピーしてから値を設定して、元の DataFrame に列を設定すると、警告が出なくなります。
どちらも [行, 列] の順番になります。
また、df[列名] で列を特定して、そこから行のインデックス、または名前を指定して、要素を参照することができます。
取得
print(df.iloc[2, 0]) # 次郎
print(df.loc['no3', '名前']) # 次郎
print(df['名前'].no3) # 次郎
print(df['名前'][2]) # 次郎
設定
df.loc['no2', '名前'] = '三郎'
df.iloc[2, 0] = '四郎'
また、以下のようにして設定しようとすると、警告が出ます。
これは、列(Series)を取得してから、列の要素を設定することになりますが、
元の DataFrame に反映されるためです。
df['名前'][1] = '三郎'
df['名前'][2] = '四郎'
# 警告
# SettingWithCopyWarning:
# A value is trying to be set on a copy of a slice from a DataFrame
上記警告は以下により消せますが、loc か iloc を使った方法に書き直した方が良いかもしれません。
参考:警告の制御
import warnings
warnings.filterwarnings('ignore')
以下のように列をコピーしてから値を設定して、元の DataFrame に列を設定すると、警告が出なくなります。
s = df['名前'].copy()
s[1] = '三郎'
s[2] = '四郎'
df['名前'] = s
4-3. いろんな取得方法
以下は「1. 生成」のソースの続きです。
1列の取得
複数列の取得
1行の取得
複数行の取得
部分的な範囲の取得
ランダム、先頭、最後の行の取得
1列の取得
s = df.iloc[:, 0]
#s = df.loc[:, '名前']
#s = df['名前']
print(type(s)) # <class 'pandas.core.series.Series'>
print(s)
# no1 太郎
# no2 花子
# no3 次郎
複数列の取得
s = df.iloc[:, [0, 1]]
#s = df.loc[:, ['名前', '国語']]
#s = df.loc[:, '名前':'国語']
print(type(s)) # <class 'pandas.core.frame.DataFrame'>
print(s)
# 名前 国語
# no1 太郎 5
# no2 花子 4
# no3 次郎 1
1行の取得
s = df.iloc[1]
#s = df.loc['no2']
print(type(s)) # <class 'pandas.core.series.Series'>
print(s['国語']) # 4
print(s)
# 名前 花子
# 国語 4
# 算数 5
# 理科 5
# 社会 4
複数行の取得
s = df.iloc[0:3]
#s = df.loc['no1':'no3']
print(type(s)) # <class 'pandas.core.frame.DataFrame'>
print(s)
# 名前 国語 算数 理科 社会
# no1 太郎 5 4 4 3
# no2 花子 4 5 5 4
# no3 次郎 1 2 1 2
部分的な範囲の取得
#s = df.loc['no1':'no2', ['国語', '算数']]
s = df.iloc[0:2, 1:3]
print(type(s))
print(s)
# 国語 算数
# no1 5 4
# no2 4 5
ランダム、先頭、最後の行の取得
import pandas as pd
df = pd.DataFrame(
[
['太郎', 5, 4, 4, 3],
['花子', 4, 5, 5, 4],
['次郎', 1, 2, 1, 2],
['三郎', 3, 3, 3, 3],
['四郎', 4, 4, 4, 4],
['五郎', 5, 5, 5, 5],
],
columns = ['名前', '国語', '算数', '理科', '社会']
)
# ランダムで3行を取得
print(df.sample(n = 3))
# 名前 国語 算数 理科 社会
# 2 次郎 1 2 1 2
# 1 花子 4 5 5 4
# 0 太郎 5 4 4 3
# 先頭の 2行を取得
print(df.head(2))
# 名前 国語 算数 理科 社会
# 0 太郎 5 4 4 3
# 1 花子 4 5 5 4
# 最後の 2行を取得
print(df.tail(2))
# 名前 国語 算数 理科 社会
# 4 四郎 4 4 4 4
# 5 五郎 5 5 5 5
4-4. 行の追加
Series を生成して、append() で追加します。
引数の name には、DataFrame の Index に該当する部分を設定します。
上記は以下のように Series を生成しても同じ動作になります。
index は要素毎のキーになります。
Series を生成せずに、辞書(連想配列)を渡して追加します。
この方法だと Index が振り直されます。
また、ignore_index = True にしないと、エラーになります。
引数の name には、DataFrame の Index に該当する部分を設定します。
d = {'名前':'三郎', '国語': 1, '算数': 2, '理科': 3, '社会': 4}
s = pd.Series(d, name = 'no4')
df = df.append(s)
# 名前 国語 算数 理科 社会
# no1 太郎 5 4 4 3
# no2 花子 4 5 5 4
# no3 次郎 1 2 1 2
# no4 三郎 1 2 3 4 [ 追加 ]
上記は以下のように Series を生成しても同じ動作になります。
index は要素毎のキーになります。
s = pd.Series(['三郎', 1, 2, 3, 4], index = df.columns, name = 'no4')
Series を生成せずに、辞書(連想配列)を渡して追加します。
この方法だと Index が振り直されます。
また、ignore_index = True にしないと、エラーになります。
d = {'名前':'三郎', '国語': 1, '算数': 2, '理科': 3, '社会': 4}
df = df.append(d, ignore_index = True)
print(df)
# 名前 国語 算数 理科 社会
# 0 太郎 5 4 4 3
# 1 花子 4 5 5 4
# 2 次郎 1 2 1 2
# 3 三郎 1 2 3 4 [ 追加 ]
4-5. 列の追加
未使用のカラムに代入すると列が追加されます。
要素数と DataFrame の行数が一致しない場合はエラーになります。
concat() で列(Series)を追加します。
DataFrame に index が指定されている場合は、
Series でも同じ index を指定する必要があります。
index が一致しない場合は、行が追加されるので要注意。
concat() で複数の列(DataFrame)を追加します。
要素数と DataFrame の行数が一致しない場合はエラーになります。
df['英語'] = [1, 2, 3]
concat() で列(Series)を追加します。
DataFrame に index が指定されている場合は、
Series でも同じ index を指定する必要があります。
index が一致しない場合は、行が追加されるので要注意。
s = pd.Series([5,4,3], index = ['no1', 'no2', 'no3'], name = '英語')
df2 = pd.concat([df, s], axis = 1)
print(df2)
concat() で複数の列(DataFrame)を追加します。
df2 = pd.DataFrame(
[
[5, 5],
[4, 4],
[3, 3],
],
index = ['no1', 'no2', 'no3'],
columns = ['体育', '音楽']
)
df3 = pd.concat([df, df2], axis = 1) #0:行 1:列
print(df3)
# 名前 国語 算数 理科 社会 体育 音楽
# no1 太郎 5 4 4 3 5 5
# no2 花子 4 5 5 4 4 4
# no3 次郎 1 2 1 2 3 3
4-6. 行・列の削除
行の削除
列の削除
df.drop('no1', axis = 0, inplace = True)
#df.drop(['no1', 'no2'], axis = 0, inplace = True)
print(df)
# 名前 国語 算数 理科 社会
# no2 花子 4 5 5 4
# no3 次郎 1 2 1 2
列の削除
df.drop('社会', axis = 1, inplace = True)
#df.drop(['理科', '社会'], axis = 1, inplace = True)
print(df)
# 名前 国語 算数 理科
# no1 太郎 5 4 4
# no2 花子 4 5 5
# no3 次郎 1 2 1
4-7. サイズ
行数と列数は shape と len() で取得できます。
print(df.shape[0]) # 行数
print(df.shape[1]) # 列数
print(df.size) # 全体の要素数 = 行数 * 列数
print(len(df)) # 行数
print(len(df.columns)) # 列数
5. CSVファイルの入出力
DataFrame を CSV 出力して、それを読み込んで画面に出力します。
index の列を使う場合は、読み込み時に index_col でインデックスの列を指定します。
import pandas as pd
# 生成
df = pd.DataFrame(
[
['太郎', 5, 4, 4, 3],
['花子', 4, 5, 5, 4],
['次郎', 1, 2, 1, 2],
],
index = ['no1', 'no2', 'no3'],
columns = ['名前', '国語', '算数', '理科', '社会']
)
# CSVファイルの書き込み
df.to_csv('test.csv', encoding="utf-8")
# CSVファイルの読み込み
df2 = pd.read_csv('test.csv', encoding="utf-8", index_col = 0)
print(df2)
# 名前 国語 算数 理科 社会
# no1 太郎 5 4 4 3
# no2 花子 4 5 5 4
# no3 次郎 1 2 1 2
出力された test.csv。行の先頭にインデックスが入っています。
,名前,国語,算数,理科,社会
no1,太郎,5,4,4,3
no2,花子,4,5,5,4
no3,次郎,1,2,1,2
インデックスを使用しない場合は以下のようにします。
# CSVファイルの書き込み
df.to_csv('test.csv', encoding = 'utf-8', index = False)
# CSVファイルの読み込み
df2 = pd.read_csv('test.csv', encoding = 'utf-8')
出力された test.csv
名前,国語,算数,理科,社会
太郎,5,4,4,3
花子,4,5,5,4
次郎,1,2,1,2
また、以下のようにして、簡単にExcelファイルの入出力も行えます。
df.to_excel('test.xlsx')
df3 = pd.read_excel('test.xlsx')
6. グラフ表示
plot() で、簡単にグラフを表示することができます。
凡例に日本語が表示されない場合は、フォント一覧から日本語フォントを探して設定してください。
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
# フォント一覧の表示
#fonts = matplotlib.font_manager.findSystemFonts()
#for f in fonts:
# print(matplotlib.font_manager.FontProperties(fname = f).get_name())
# フォントの設定
plt.rcParams["font.family"] = 'Yu Mincho'
df = pd.DataFrame(
[
['太郎', 5, 4, 4, 3],
['花子', 4, 5, 5, 4],
['次郎', 1, 2, 1, 2],
],
index = ['no1', 'no2', 'no3'],
columns = ['名前', '国語', '算数', '理科', '社会']
)
df.plot(kind = 'bar')
plt.show()
7. numpy.ndarray との相互変換
import pandas as pd
df = pd.DataFrame(
[
['太郎', 5, 4, 4, 3],
['花子', 4, 5, 5, 4],
['次郎', 1, 2, 1, 2],
],
index = ['no1', 'no2', 'no3'],
columns = ['名前', '国語', '算数', '理科', '社会']
)
# pandas -> numpy
nd = df.values
print(type(nd)) # <class 'numpy.ndarray'>
print(nd)
# [['太郎' 5 4 4 3]
# ['花子' 4 5 5 4]
# ['次郎' 1 2 1 2]]
# numpy -> pandas
df2 = pd.DataFrame(nd) # <class 'pandas.core.frame.DataFrame'>
print(type(df2))
print(df2)
# 0 1 2 3 4
# 0 太郎 5 4 4 3
# 1 花子 4 5 5 4
# 2 次郎 1 2 1 2
index の列を使う場合は、読み込み時に index_col でインデックスの列を指定します。
import pandas as pd
# 生成
df = pd.DataFrame(
[
['太郎', 5, 4, 4, 3],
['花子', 4, 5, 5, 4],
['次郎', 1, 2, 1, 2],
],
index = ['no1', 'no2', 'no3'],
columns = ['名前', '国語', '算数', '理科', '社会']
)
# CSVファイルの書き込み
df.to_csv('test.csv', encoding="utf-8")
# CSVファイルの読み込み
df2 = pd.read_csv('test.csv', encoding="utf-8", index_col = 0)
print(df2)
# 名前 国語 算数 理科 社会
# no1 太郎 5 4 4 3
# no2 花子 4 5 5 4
# no3 次郎 1 2 1 2
出力された test.csv。行の先頭にインデックスが入っています。
,名前,国語,算数,理科,社会
no1,太郎,5,4,4,3
no2,花子,4,5,5,4
no3,次郎,1,2,1,2
インデックスを使用しない場合は以下のようにします。
# CSVファイルの書き込み
df.to_csv('test.csv', encoding = 'utf-8', index = False)
# CSVファイルの読み込み
df2 = pd.read_csv('test.csv', encoding = 'utf-8')
出力された test.csv
名前,国語,算数,理科,社会
太郎,5,4,4,3
花子,4,5,5,4
次郎,1,2,1,2
また、以下のようにして、簡単にExcelファイルの入出力も行えます。
df.to_excel('test.xlsx')
df3 = pd.read_excel('test.xlsx')
凡例に日本語が表示されない場合は、フォント一覧から日本語フォントを探して設定してください。
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
# フォント一覧の表示
#fonts = matplotlib.font_manager.findSystemFonts()
#for f in fonts:
# print(matplotlib.font_manager.FontProperties(fname = f).get_name())
# フォントの設定
plt.rcParams["font.family"] = 'Yu Mincho'
df = pd.DataFrame(
[
['太郎', 5, 4, 4, 3],
['花子', 4, 5, 5, 4],
['次郎', 1, 2, 1, 2],
],
index = ['no1', 'no2', 'no3'],
columns = ['名前', '国語', '算数', '理科', '社会']
)
df.plot(kind = 'bar')
plt.show()
import pandas as pd
df = pd.DataFrame(
[
['太郎', 5, 4, 4, 3],
['花子', 4, 5, 5, 4],
['次郎', 1, 2, 1, 2],
],
index = ['no1', 'no2', 'no3'],
columns = ['名前', '国語', '算数', '理科', '社会']
)
# pandas -> numpy
nd = df.values
print(type(nd)) # <class 'numpy.ndarray'>
print(nd)
# [['太郎' 5 4 4 3]
# ['花子' 4 5 5 4]
# ['次郎' 1 2 1 2]]
# numpy -> pandas
df2 = pd.DataFrame(nd) # <class 'pandas.core.frame.DataFrame'>
print(type(df2))
print(df2)
# 0 1 2 3 4
# 0 太郎 5 4 4 3
# 1 花子 4 5 5 4
# 2 次郎 1 2 1 2