Python用データ分析ライブラリとしてデファクトスタンダードとなっているpandasの基本的な使い方について、まとめました。
本記事は、公式ドキュメントの10 Minutes to pandasをベースに加筆・変更して記述しています。
ただし少しでも分かり易くする為に、元の記事をそのまま翻訳するのではなく、下記の点に留意した改善を加えています。
- 使用しているAPIのリファレンスを確認し易いように、出来るだけリファレンスへのリンクを併記。
- pandas実行環境が手元にない読者の方(電車の中でスマホで勉強中の方など)を意識して、処理前後で確認したくなるであろうデータの状態を出来るだけ都度表示。
- 公式「10 Minutes to pandas」は、同じDataFrameにどんどん処理をしていく形式を取っている箇所が多数あります。その為、処理前のDataFrameがどんな状態だったか、ずっと上までスクロールして戻って確認しなければならないことがあり、理解の妨げになることがあります。
備考
pandasやそのドキュメント等のライセンスについては、「データ分析ライブラリpandasのライセンス」に記載しています。
目次
1. pandasについて
pandasは、高速で柔軟なデータ構造を提供するPythonパッケージです。Pythonで実用的なデータ分析をする際の、高水準な基盤となるべく開発されています。
pandasでは、様々な種類のデータを扱うことができます。
- ExcelやSQLテーブルで扱われるような、複数の型が混在する表データ
- 時系列のデータ(ソートされているもの、いないもの)
- 行列データ
- その他の観測データや統計データ
pandasの主要なデータ構造は、Series(1次元)とDataFrame(2次元)です。DataFrameは、Rで言うところのdata.frameに当たります。
pandasは、数値計算ライブラリNumPyの上に構築されていて、その他の科学計算系ライブラリと一緒に使うことを意図して開発されています。また高速に動作させる為、内部アルゴリズムはCythonやC言語で最適化・実装されています。
3. 準備
慣習に習い、各種ライブラリを下記のようにインポートします。
1 2 3 | import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
|
4. オブジェクトの生成[1]
4.1. リストからSeriesを生成
pandasがデフォルトの整数インデックスを作成します。
1 2 | s = pd.Series([1, 3, 5, np.nan, 6, 8])
s
|
0 1.0 1 3.0 2 5.0 3 NaN 4 6.0 5 8.0 dtype: float64
4.2. 日時のインデックスとラベル付きカラム(列)を持ったDataFrameを生成[25]
まず、date_range関数を使って、2017年1月1日から6日分のDatetimeIndexオブジェクトを作成します。
1 2 | dates = pd.date_range('20170101', periods=6)
dates
|
DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03', '2017-01-04', '2017-01-05', '2017-01-06'], dtype='datetime64[ns]', freq='D')
それをDataFrameのコンストラクタのindex引数に渡します。その他、引数は下記の通り渡します。
- data引数(第1引数):NumPyのrandn関数で生成した6x4の乱数の配列
- index引数:DatetimeIndexオブジェクト
- columns引数:リスト['A', 'B', 'C', 'D']
1 2 | df = pd.DataFrame(np.random.randn(6,4), index=dates, columns=list('ABCD'))
df
|
A | B | C | D | |
---|---|---|---|---|
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 |
4.3. 辞書オブジェクトから、DataFrameを生成[24][25]
辞書オブジェクトの値一つ一つは、Seriesに変換できる形式である必要があります。
1 2 3 4 5 6 7 | df2 = pd.DataFrame({ 'A' : 1.,
'B' : pd.Timestamp('20170102'),
'C' : pd.Series(1, index=list(range(4)), dtype='float32'),
'D' : np.array([3] * 4, dtype='int32'),
'E' : pd.Categorical(["test", "train", "test", "train"]),
'F' : 'foo' })
df2
|
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
0 | 1.0 | 2017-01-02 | 1.0 | 3 | test | foo |
1 | 1.0 | 2017-01-02 | 1.0 | 3 | train | foo |
2 | 1.0 | 2017-01-02 | 1.0 | 3 | test | foo |
3 | 1.0 | 2017-01-02 | 1.0 | 3 | train | foo |
4.4. 出来上がったDataFrameの確認
各カラム(列)のデータ形式を確認します。
1 | df2.dtypes
|
A float64 B datetime64[ns] C float32 D int32 E category F object dtype: object
カラム(列)名は、そのままプロパティとしてアクセスすることができます。
2 | df2.A
|
0 1.0 1 1.0 2 1.0 3 1.0 Name: A, dtype: float64
3 | df2.B
|
0 2017-01-02 1 2017-01-02 2 2017-01-02 3 2017-01-02 Name: B, dtype: datetime64[ns]
4 | df2.C
|
0 1.0 1 1.0 2 1.0 3 1.0 Name: C, dtype: float32
5 | df2.D
|
0 3 1 3 2 3 3 3 Name: D, dtype: int32
6 | df2.E
|
0 test 1 train 2 test 3 train Name: E, dtype: category Categories (2, object): [test, train]
7 | df2.F
|
0 foo 1 foo 2 foo 3 foo Name: F, dtype: object
5. データの閲覧[2]
DataFrameの最初と最後を確認するには、headメソッドやtailメソッドを使います。
5.1. 元のDataFrameを確認
処理を理解し易いように、まずは元のDataFrameを確認しておきます。
1 | df
|
A | B | C | D | |
---|---|---|---|---|
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 |
5.2. DataFrameの最初の5行を表示
DataFrameの最初を確認するには、headメソッドを使います[27]。 引数を省略した場合は、5行目までが表示されます。
1 | df.head()
|
A | B | C | D | |
---|---|---|---|---|
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 |
5.3. DataFrameの最後の3行を表示
DataFrameの最後を確認するには、tailメソッドを使います[27]。
1 | df.tail(3)
|
A | B | C | D | |
---|---|---|---|---|
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 |
5.4. インデックスを表示[23]
1 | df.index
|
DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03', '2017-01-04', '2017-01-05', '2017-01-06'], dtype='datetime64[ns]', freq='D')
5.6. 値を表示
1 | df.values
|
array([[ 0.4691, -0.2829, -1.5091, -1.1356], [ 1.2121, -0.1732, 0.1192, -1.0442], [-0.8618, -2.1046, -0.4949, 1.0718], [ 0.7216, -0.7068, -1.0396, 0.2719], [-0.425 , 0.567 , 0.2762, -1.0874], [-0.6737, 0.1136, -1.4784, 0.525 ]])
5.7. 統計的な概要を表示
DataFrame.describeメソッドを使います。
1 | df.describe()
|
A | B | C | D | |
---|---|---|---|---|
count | 6.000000 | 6.000000 | 6.000000 | 6.000000 |
mean | 0.073711 | -0.431125 | -0.687758 | -0.233103 |
std | 0.843157 | 0.922818 | 0.779887 | 0.973118 |
min | -0.861849 | -2.104569 | -1.509059 | -1.135632 |
25% | -0.611510 | -0.600794 | -1.368714 | -1.076610 |
50% | 0.022070 | -0.228039 | -0.767252 | -0.386188 |
75% | 0.658444 | 0.041933 | -0.034326 | 0.461706 |
max | 1.212112 | 0.567020 | 0.276232 | 1.071804 |
5.8. DataFrameの転置[24]
DataFrame.Tプロパティで転置させることができます。
5.8.1. 元のDataFrameを確認
処理を理解し易いように、まずは元のDataFrameを確認しておきます。
1 | df
|
A | B | C | D | |
---|---|---|---|---|
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 |
5.8.2. 転置したDataFrame
DataFrame.Tプロパティで、行と列が入れ替わったDataFrameを取得できます。
1 | df.T
|
2017-01-01 00:00:00 | 2017-01-02 00:00:00 | 2017-01-03 00:00:00 | 2017-01-04 00:00:00 | 2017-01-05 00:00:00 | 2017-01-06 00:00:00 | |
---|---|---|---|---|---|---|
A | 0.469112 | 1.212112 | -0.861849 | 0.721555 | -0.424972 | -0.673690 |
B | -0.282863 | -0.173215 | -2.104569 | -0.706771 | 0.567020 | 0.113648 |
C | -1.509059 | 0.119209 | -0.494929 | -1.039575 | 0.276232 | -1.478427 |
D | -1.135632 | -1.044236 | 1.071804 | 0.271860 | -1.087401 | 0.524988 |
5.9. インデックスやカラム(列)の並び替え
インデックスやカラム(列)を並び替えるには、DataFrame.sort_indexメソッドを使います。
- axis引数に1を渡すと、カラム(列)を(行方向に)並び替えます。
- axis引数に0を渡す(あるいは指定をしない)と、インデックスを(列方向に)並び替えます。
- ascending引数にFalseを渡すと、降順に並び替えます。
5.9.1. インデックスを降順に並び替え
1 | df.sort_index(axis=0, ascending=False)
|
A | B | C | D | |
---|---|---|---|---|
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 |
5.9.2. カラム(列)を降順に並び替え
1 | df.sort_index(axis=1, ascending=False)
|
D | C | B | A | |
---|---|---|---|---|
2017-01-01 | -1.135632 | -1.509059 | -0.282863 | 0.469112 |
2017-01-02 | -1.044236 | 0.119209 | -0.173215 | 1.212112 |
2017-01-03 | 1.071804 | -0.494929 | -2.104569 | -0.861849 |
2017-01-04 | 0.271860 | -1.039575 | -0.706771 | 0.721555 |
2017-01-05 | -1.087401 | 0.276232 | 0.567020 | -0.424972 |
2017-01-06 | 0.524988 | -1.478427 | 0.113648 | -0.673690 |
5.10. 値の並び替え
値を並び替えるには、DataFrame.sort_valuesメソッドを使います[24]。
- axis引数に1を渡すと、カラム間で(行方向に)並び替えます。
- axis引数に0を渡す(あるいは指定をしない)と、インデックス間で(列方向に)並び替えます。
- ascending引数にFalseを渡すと、降順に並び替えます。
5.10.1. カラム(列)「B」の値で昇順に並び替え
1 | df.sort_values(by='B')
|
A | B | C | D | |
---|---|---|---|---|
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 |
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 |
5.10.2. カラム(列)「C」の値で降順に並び替え
1 | df.sort_values(by='C', ascending=False)
|
A | B | C | D | |
---|---|---|---|---|
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 |
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 |
6. 選択処理
6.1. 注意
インタラクティブな環境で使う場合など、標準的なpythonやNumPyの直感的な記法の方が便利な場合もありますが、製品コードではより最適化されているatプロパティ、iatプロパティ、locプロパティ、ilocプロパティ を使うことを、開発元は推奨しています。
6.2. 取得処理
6.2.1. 元の DataFrameを確認
処理を理解し易いように、まずは元のDataFrameを確認しておきます。
1 | df
|
A | B | C | D | |
---|---|---|---|---|
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 |
6.2.2. カラム(列)名を1つ与えて、Seriesを生成 [23]
これは、df.Aと同等です。
1 | df['A']
|
2017-01-01 0.469112 2017-01-02 1.212112 2017-01-03 -0.861849 2017-01-04 0.721555 2017-01-05 -0.424972 2017-01-06 -0.673690 Freq: D, Name: A, dtype: float64
6.2.3. スライスで、(行の)選択範囲を抽出[26]
6.2.3.1. インデックスの0番目から3行分を抽出
1 | df[0:3]
|
A | B | C | D | |
---|---|---|---|---|
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 |
6.2.3.2. インデックス「2017-01-02」から「2017-01-04」 までを抽出
1 | df['20170102':'20170104']
|
A | B | C | D | |
---|---|---|---|---|
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 |
6.3. ラベルを使った選択[3]
6.3.1. 元のDataFrame を確認
処理を理解し易いように、まずは元のDataFrameを確認しておきます。
1 | df
|
A | B | C | D | |
---|---|---|---|---|
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 |
datesも確認しておきます。
1 | dates
|
DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03', '2017-01-04', '2017-01-05', '2017-01-06'], dtype='datetime64[ns]', freq='D')
6.3.2. locプロパティで行を抽出
DataFrame.locプロパティにインデックスの値を1つ渡して、その行を抽出します。
- datesはdfを作成する時に作ったインデックスです。
- dates[0]は2017/1/1の0時0分を表すTimestampオブジェクトです。
1 | df.loc[dates[0]]
|
A 0.469112 B -0.282863 C -1.509059 D -1.135632 Name: 2017-01-01 00:00:00, dtype: float64
6.3.3. locプロパティで行と列を抽出
DataFrame.locプロパティにインデックスのスライスとカラム(列)名のリストを渡して、行と列を絞り込みます。(":"は「全て」を表すスライスです)
1 | df.loc[:, ['A','B']]
|
A | B | |
---|---|---|
2017-01-01 | 0.469112 | -0.282863 |
2017-01-02 | 1.212112 | -0.173215 |
2017-01-03 | -0.861849 | -2.104569 |
2017-01-04 | 0.721555 | -0.706771 |
2017-01-05 | -0.424972 | 0.567020 |
2017-01-06 | -0.673690 | 0.113648 |
絞り込み結果には、渡したスライスの始まり(2017-01-02)と終わり(2017-01-04)が含まれます。
1 | df.loc['20170102':'20170104', ['A','B']]
|
A | B | |
---|---|---|
2017-01-02 | 1.212112 | -0.173215 |
2017-01-03 | -0.861849 | -2.104569 |
2017-01-04 | 0.721555 | -0.706771 |
インデックスのラベルを1つだけ渡すと、Seriesが返ってきます。(2次元→1次元)
1 | df.loc['20170102', ['A', 'B']]
|
A 1.212112 B -0.173215 Name: 2017-01-02 00:00:00, dtype: float64
6.3.4. locプロパティで値を取得[23]
DataFrame.locプロパティにインデックスとカラム(列)名を1つずつ渡すと、値が返ってきます。
1 | df.loc[dates[0], 'A']
|
0.46911229990718628
6.4. 位置(n番目)を使った選択[4]
6.4.1. 元のDataFrameを確認
処理を理解し易いように、まずは元のDataFrameを確認しておきます。
1 | df
|
A | B | C | D | |
---|---|---|---|---|
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 |
6.4.2. 位置で行を抽出
DataFrame.ilocプロパティに整数を1つ渡すと、その位置の行が返ってきます。
1 | df.iloc[3]
|
A 0.721555 B -0.706771 C -1.039575 D 0.271860 Name: 2017-01-04 00:00:00, dtype: float64
6.4.3. 整数のスライスで選択
DataFrame.ilocプロパティに整数のスライスを渡すと、その範囲の行とカラム(列)が返ってきます。整数のスライスはNumPyやpythonと同様です。
1 | df.iloc[3:5, 0:2]
|
A | B | |
---|---|---|
2017-01-04 | 0.721555 | -0.706771 |
2017-01-05 | -0.424972 | 0.567020 |
6.4.4. 整数のリストで選択[23]
DataFrame.ilocプロパティに整数のリストを渡すと、それらの位置の行とカラム(列)が返ってきます。
1 | df.iloc[[1, 2, 4], [0, 2]]
|
A | C | |
---|---|---|
2017-01-02 | 1.212112 | 0.119209 |
2017-01-03 | -0.861849 | -0.494929 |
2017-01-05 | -0.424972 | 0.276232 |
6.4.5. 行の位置だけで選択
カラム(列)の位置を":"にすることで、行の位置だけで選択できます。(カラム(列)の範囲を「全て」に指定できます)
1 | df.iloc[1:3, :]
|
A | B | C | D | |
---|---|---|---|---|
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 |
6.4.6. カラム(列)の位置だけで選択
同様に、行の位置を":"にすることで、カラム(列)の位置だけで選択できます。(行の範囲を「全て」に指定できます)
1 | df.iloc[:, 1:3]
|
B | C | |
---|---|---|
2017-01-01 | -0.282863 | -1.509059 |
2017-01-02 | -0.173215 | 0.119209 |
2017-01-03 | -2.104569 | -0.494929 |
2017-01-04 | -0.706771 | -1.039575 |
2017-01-05 | 0.567020 | 0.276232 |
2017-01-06 | 0.113648 | -1.478427 |
6.4.7. 行とカラム(列)の位置で値を取得
1 | df.iloc[1, 1]
|
-0.17321464905330858
6.5. ブーリアン選択
6.5.1. 元のDataFrameを確認
処理を理解し易いように、まずは元のDataFrameを確認しておきます。
1 | df
|
A | B | C | D | |
---|---|---|---|---|
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 |
6.5.2. ひとつのカラム(列)の値を使って選択
カラム(列)「A」の値が0より大きい行だけが返ってきます。
1 | df[df.A > 0]
|
A | B | C | D | |
---|---|---|---|---|
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 |
6.5.3. 条件に合う値のみを抽出[24][23]
この場合は、条件に合わない所はNaNになります。
1 | df[df > 0]
|
A | B | C | D | |
---|---|---|---|---|
2017-01-01 | 0.469112 | NaN | NaN | NaN |
2017-01-02 | 1.212112 | NaN | 0.119209 | NaN |
2017-01-03 | NaN | NaN | NaN | 1.071804 |
2017-01-04 | 0.721555 | NaN | NaN | 0.271860 |
2017-01-05 | NaN | 0.567020 | 0.276232 | NaN |
2017-01-06 | NaN | 0.113648 | NaN | 0.524988 |
6.5.4. isinメソッドを使った選択
まず、動作確認用にdfにカラム(列)「E」を追加したdf2を作成します。
1 2 3 | df2 = df.copy()
df2['E'] = ['one', 'one', 'two', 'three', 'four', 'three']
df2
|
A | B | C | D | E | |
---|---|---|---|---|---|
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 | one |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 | one |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 | two |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 | three |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 | four |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 | three |
カラム(列)「E」の値が、Series.isinメソッドに渡したリスト['two', 'four']の要素と同じ行だけが返ってきます。
1 | df2[df2['E'].isin(['two', 'four'])]
|
A | B | C | D | E | |
---|---|---|---|---|---|
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 | two |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 | four |
6.6. 値のセット
処理を理解し易いように、まずは元のDataFrameを確認しておきます。
1 | df
|
A | B | C | D | |
---|---|---|---|---|
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 |
datesも確認しておきます。
1 | dates
|
DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03', '2017-01-04', '2017-01-05', '2017-01-06'], dtype='datetime64[ns]', freq='D')
6.6.1. 新しいカラム(列)に値をセット
まず、下記のようなSeriesオブジェクトs1を作成します。
1 2 | s1 = pd.Series([1,2,3,4,5,6], index=pd.date_range('20170102', periods=6))
s1
|
2017-01-02 1 2017-01-03 2 2017-01-04 3 2017-01-05 4 2017-01-06 5 2017-01-07 6 Freq: D, dtype: int64
dfのカラム(列)「F」にs1をセットすると、自動的にインデックスに合わせて値が格納されます。
1 2 | df['F'] = s1
df
|
A | B | C | D | F | |
---|---|---|---|---|---|
2017-01-01 | 0.469112 | -0.282863 | -1.509059 | -1.135632 | NaN |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 | 1.0 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 | 2.0 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 | 3.0 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 | 4.0 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 | 5.0 |
6.6.2. ラベル指定で値をセット
1 2 | df.at[dates[0], 'A'] = 0
df
|
A | B | C | D | F | |
---|---|---|---|---|---|
2017-01-01 | 0.000000 | -0.282863 | -1.509059 | -1.135632 | NaN |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 | 1.0 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 | 2.0 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 | 3.0 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 | 4.0 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 | 5.0 |
6.6.3. 位置指定で値をセット
1 2 | df.iat[0,1] = 0
df
|
A | B | C | D | F | |
---|---|---|---|---|---|
2017-01-01 | 0.000000 | 0.000000 | -1.509059 | -1.135632 | NaN |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | -1.044236 | 1.0 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 1.071804 | 2.0 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 0.271860 | 3.0 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | -1.087401 | 4.0 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 0.524988 | 5.0 |
6.6.4. NumPy配列の値をセット
まず、下記のようなNumPy配列を作成します。
1 | np.array([5] * len(df))
|
array([5, 5, 5, 5, 5, 5])
それをカラム(列)「D」にセットします。
1 2 | df.loc[:, 'D'] = np.array([5] * len(df))
df
|
A | B | C | D | F | |
---|---|---|---|---|---|
2017-01-01 | 0.000000 | 0.000000 | -1.509059 | 5 | NaN |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | 5 | 1.0 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 5 | 2.0 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 5 | 3.0 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | 5 | 4.0 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 5 | 5.0 |
6.6.5. 条件に合う値だけを上書き
正の値を全て負にします。
1 2 3 | df2 = df.copy()
df2[df2 > 0] = -df2
df2
|
A | B | C | D | F | |
---|---|---|---|---|---|
2017-01-01 | 0.000000 | 0.000000 | -1.509059 | -5 | NaN |
2017-01-02 | -1.212112 | -0.173215 | -0.119209 | -5 | -1.0 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | -5 | -2.0 |
2017-01-04 | -0.721555 | -0.706771 | -1.039575 | -5 | -3.0 |
2017-01-05 | -0.424972 | -0.567020 | -0.276232 | -5 | -4.0 |
2017-01-06 | -0.673690 | -0.113648 | -1.478427 | -5 | -5.0 |
7. 不明値(欠測値)(NaN)[5]
pandasでは、不明値(欠測値)を表現するのに主にNumPyのNaN(np.nan)を使います。基本的にNaNは計算処理の対象外になります。
7.1. 元のDataFrameを確認
処理を理解し易いように、まずは元のDataFrameを確認しておきます。
1 | df
|
A | B | C | D | F | |
---|---|---|---|---|---|
2017-01-01 | 0.000000 | 0.000000 | -1.509059 | 5 | NaN |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | 5 | 1.0 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 5 | 2.0 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 5 | 3.0 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | 5 | 4.0 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 5 | 5.0 |
datesも確認しておきます。
1 | dates
|
DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03', '2017-01-04', '2017-01-05', '2017-01-06'], dtype='datetime64[ns]', freq='D')
7.2. 行・カラム(列)の変更/追加/削除
DataFrame.reindexメソッドを使えば、行あるいはカラム(列)を変更/追加/削除することができます。DataFrame.reindexメソッドは、元のDataFrameから作ったコピーを返します。 (元のDataFrameは書き換えられません)
新しくできたセルには、NaNが入ります。
1 | df.reindex(index=dates[0:4], columns=list(df.columns) + ['E'])
|
A | B | C | D | F | E | |
---|---|---|---|---|---|---|
2017-01-01 | 0.000000 | 0.000000 | -1.509059 | 5 | NaN | NaN |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | 5 | 1.0 | NaN |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 5 | 2.0 | NaN |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 5 | 3.0 | NaN |
新しくできたセルの一部に1をセットします。
1 2 3 | df1 = df.reindex(index=dates[0:4], columns=list(df.columns) + ['E'])
df1.loc[dates[0]:dates[1], 'E'] = 1
df1
|
A | B | C | D | F | E | |
---|---|---|---|---|---|---|
2017-01-01 | 0.000000 | 0.000000 | -1.509059 | 5 | NaN | 1.0 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | 5 | 1.0 | 1.0 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 5 | 2.0 | NaN |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 5 | 3.0 | NaN |
7.3. 不明値(欠測値)の削除[24][23]
DataFrame.dropnaメソッドで不明値(欠測値)NaNが存在する行を削除します。
1 | df1.dropna(how='any')
|
A | B | C | D | F | E | |
---|---|---|---|---|---|---|
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | 5 | 1.0 | 1.0 |
DataFrame.fillnaメソッドで不明値(欠測値)NaNを5で埋めます。
1 | df1.fillna(value=5)
|
A | B | C | D | F | E | |
---|---|---|---|---|---|---|
2017-01-01 | 0.000000 | 0.000000 | -1.509059 | 5 | 5.0 | 1.0 |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | 5 | 1.0 | 1.0 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 5 | 2.0 | 5.0 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 5 | 3.0 | 5.0 |
DataFrame.isnaメソッドは、各セルが不明値(欠測値)NaNかどうかをTrueかFalseで返します。
1 | pd.isna(df1)
|
A | B | C | D | F | E | |
---|---|---|---|---|---|---|
2017-01-01 | False | False | False | False | True | False |
2017-01-02 | False | False | False | False | False | False |
2017-01-03 | False | False | False | False | False | True |
2017-01-04 | False | False | False | False | False | True |
8. 演算処理[6]
8.1. 統計値
演算処理は、基本的に不明値(欠測値)NaNを除外して行われます。
8.1.1. 元の DataFrameを確認
処理を理解し易いように、まずは元のDataFrameを確認しておきます。
1 | df
|
A | B | C | D | F | |
---|---|---|---|---|---|
2017-01-01 | 0.000000 | 0.000000 | -1.509059 | 5 | NaN |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | 5 | 1.0 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 5 | 2.0 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 5 | 3.0 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | 5 | 4.0 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 5 | 5.0 |
datesも確認しておきます。
1 | dates
|
DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03', '2017-01-04', '2017-01-05', '2017-01-06'], dtype='datetime64[ns]', freq='D')
8.1.2. 平均値の取得
DataFrame.meanメソッドで各カラム(列)の数値の平均値が返ってきます。
1 | df.mean()
|
A -0.004474 B -0.383981 C -0.687758 D 5.000000 F 3.000000 dtype: float64
DataFrame.meanメソッドの引数に1を渡すとカラム間の(行方向の)平均値が返ってきます。
1 | df.mean(1)
|
2017-01-01 0.872735 2017-01-02 1.431621 2017-01-03 0.707731 2017-01-04 1.395042 2017-01-05 1.883656 2017-01-06 1.592306 Freq: D, dtype: float64
もう少し明示的に書くと下記のようになります。
1 | df.mean(axis=1)
|
2017-01-01 0.872735 2017-01-02 1.431621 2017-01-03 0.707731 2017-01-04 1.395042 2017-01-05 1.883656 2017-01-06 1.592306 Freq: D, dtype: float64
8.1.3. 異なる次元のオブジェクト間の演算
異なる次元のオブジェクト間で演算をする場合、pandasは指定した方向に自動的に演算を展開します。
まず下記のようなSeriesを作ります。
1 2 | s = pd.Series([1,3,4,np.nan,6,8], index=dates).shift(2)
s
|
2017-01-01 NaN 2017-01-02 NaN 2017-01-03 1.0 2017-01-04 3.0 2017-01-05 4.0 2017-01-06 NaN Freq: D, dtype: float64
これは、下記のようなSeriesを、Series.shiftメソッドでインデックスを2日ずらしたSeriesです。
1 | pd.Series([1,3,4,np.nan,6,8], index=dates)
|
2017-01-01 1.0 2017-01-02 3.0 2017-01-03 4.0 2017-01-04 NaN 2017-01-05 6.0 2017-01-06 8.0 Freq: D, dtype: float64
これをDataFrame.subメソッドを使って、DataFrameから引きます。
1 | df.sub(s, axis='index')
|
A | B | C | D | F | |
---|---|---|---|---|---|
2017-01-01 | NaN | NaN | NaN | NaN | NaN |
2017-01-02 | NaN | NaN | NaN | NaN | NaN |
2017-01-03 | -1.861849 | -3.104569 | -1.494929 | 4.0 | 1.0 |
2017-01-04 | -2.278445 | -3.706771 | -4.039575 | 2.0 | 0.0 |
2017-01-05 | -4.424972 | -3.432980 | -3.723768 | 1.0 | 0.0 |
2017-01-06 | NaN | NaN | NaN | NaN | NaN |
8.2. 関数の適用
8.2.1. 元の DataFrameを確認
処理を理解し易いように、まずは元のDataFrameを確認しておきます。
1 | df
|
A | B | C | D | F | |
---|---|---|---|---|---|
2017-01-01 | 0.000000 | 0.000000 | -1.509059 | 5 | NaN |
2017-01-02 | 1.212112 | -0.173215 | 0.119209 | 5 | 1.0 |
2017-01-03 | -0.861849 | -2.104569 | -0.494929 | 5 | 2.0 |
2017-01-04 | 0.721555 | -0.706771 | -1.039575 | 5 | 3.0 |
2017-01-05 | -0.424972 | 0.567020 | 0.276232 | 5 | 4.0 |
2017-01-06 | -0.673690 | 0.113648 | -1.478427 | 5 | 5.0 |
8.2.2. 各カラム(列)への関数の適用
DataFrame.apply メソッドに関数を渡すと、各データにその関数を適用することができます。下記の例では、各カラム(列)のSeriesにNumPyのcumsum関数を適用して、累積和にしています。
1 | df.apply(np.cumsum)
|
A | B | C | D | F | |
---|---|---|---|---|---|
2017-01-01 | 0.000000 | 0.000000 | -1.509059 | 5 | NaN |
2017-01-02 | 1.212112 | -0.173215 | -1.389850 | 10 | 1.0 |
2017-01-03 | 0.350263 | -2.277784 | -1.884779 | 15 | 3.0 |
2017-01-04 | 1.071818 | -2.984555 | -2.924354 | 20 | 6.0 |
2017-01-05 | 0.646846 | -2.417535 | -2.648122 | 25 | 10.0 |
2017-01-06 | -0.026844 | -2.303886 | -4.126549 | 30 | 15.0 |
8.3. ヒストグラム化[7]
ヒストグラム化には、Series.value_countsメソッドを使います。
例としてまずランダムな整数値のSeriesを作成します。
1 2 | s = pd.Series(np.random.randint(0, 7, size=10))
s
|
0 4 1 2 2 1 3 2 4 6 5 4 6 4 7 6 8 4 9 4 dtype: int64
Series.value_countsメソッドは、各値が何回ずつ登場するのかを返してくれます。
1 | s.value_counts()
|
4 5 6 2 2 2 1 1 dtype: int64
8.4. 文字列処理[8]
Seriesは文字列処理の為のstrアクセサを備えています。
例を示す為にまず文字列を値として持つSeriesを作成します。
1 2 | s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])
s
|
0 A 1 B 2 C 3 Aaba 4 Baca 5 NaN 6 CABA 7 dog 8 cat dtype: object
例えばSeries.str.lowerメソッドは文字列を小文字にします。
1 | s.str.lower()
|
0 a 1 b 2 c 3 aaba 4 baca 5 NaN 6 caba 7 dog 8 cat dtype: object
9. マージ
9.1. 連結(concat)[9]
SeriesやDataFrame、Panelを連結するのには、concat関数を使います。
例を示す為にまずは下記のようなDataFrameを用意します。
1 2 | df = pd.DataFrame(np.random.randn(10, 4))
df
|
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | -0.548702 | 1.467327 | -1.015962 | -0.483075 |
1 | 1.637550 | -1.217659 | -0.291519 | -1.745505 |
2 | -0.263952 | 0.991460 | -0.919069 | 0.266046 |
3 | -0.709661 | 1.669052 | 1.037882 | -1.705775 |
4 | -0.919854 | -0.042379 | 1.247642 | -0.009920 |
5 | 0.290213 | 0.495767 | 0.362949 | 1.548106 |
6 | -1.131345 | -0.089329 | 0.337863 | -0.945867 |
7 | -0.932132 | 1.956030 | 0.017587 | -0.016692 |
8 | -0.575247 | 0.254161 | -1.143704 | 0.215897 |
9 | 1.193555 | -0.077118 | -0.408530 | -0.862495 |
dfの一部を要素に持つリストを作ります。
1 2 | pieces = [df[:3], df[3:7], df[7:]]
pieces
|
[ 0 1 2 3 0 -0.548702 1.467327 -1.015962 -0.483075 1 1.637550 -1.217659 -0.291519 -1.745505 2 -0.263952 0.991460 -0.919069 0.266046, 0 1 2 3 3 -0.709661 1.669052 1.037882 -1.705775 4 -0.919854 -0.042379 1.247642 -0.009920 5 0.290213 0.495767 0.362949 1.548106 6 -1.131345 -0.089329 0.337863 -0.945867, 0 1 2 3 7 -0.932132 1.956030 0.017587 -0.016692 8 -0.575247 0.254161 -1.143704 0.215897 9 1.193555 -0.077118 -0.408530 -0.862495]
リストの各要素を確認すると、こうなっています。
1 | pieces[0]
|
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | -0.548702 | 1.467327 | -1.015962 | -0.483075 |
1 | 1.637550 | -1.217659 | -0.291519 | -1.745505 |
2 | -0.263952 | 0.991460 | -0.919069 | 0.266046 |
1 | pieces[1]
|
0 | 1 | 2 | 3 | |
---|---|---|---|---|
3 | -0.709661 | 1.669052 | 1.037882 | -1.705775 |
4 | -0.919854 | -0.042379 | 1.247642 | -0.009920 |
5 | 0.290213 | 0.495767 | 0.362949 | 1.548106 |
6 | -1.131345 | -0.089329 | 0.337863 | -0.945867 |
1 | pieces[2]
|
0 | 1 | 2 | 3 | |
---|---|---|---|---|
7 | -0.932132 | 1.956030 | 0.017587 | -0.016692 |
8 | -0.575247 | 0.254161 | -1.143704 | 0.215897 |
9 | 1.193555 | -0.077118 | -0.408530 | -0.862495 |
concat関数にこのリストを渡すと、各要素を連結したDataFrameを返します。[25]
1 | pd.concat(pieces)
|
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | -0.548702 | 1.467327 | -1.015962 | -0.483075 |
1 | 1.637550 | -1.217659 | -0.291519 | -1.745505 |
2 | -0.263952 | 0.991460 | -0.919069 | 0.266046 |
3 | -0.709661 | 1.669052 | 1.037882 | -1.705775 |
4 | -0.919854 | -0.042379 | 1.247642 | -0.009920 |
5 | 0.290213 | 0.495767 | 0.362949 | 1.548106 |
6 | -1.131345 | -0.089329 | 0.337863 | -0.945867 |
7 | -0.932132 | 1.956030 | 0.017587 | -0.016692 |
8 | -0.575247 | 0.254161 | -1.143704 | 0.215897 |
9 | 1.193555 | -0.077118 | -0.408530 | -0.862495 |
9.2. 結合(join)[10]
SQLスタイルのマージには、merge関数を使います。
1 2 | left = pd.DataFrame({'key': ['foo', 'bar'], 'lval': [1, 2]})
left
|
key | lval | |
---|---|---|
0 | foo | 1 |
1 | bar | 2 |
1 2 | right = pd.DataFrame({'key': ['foo', 'bar'], 'rval': [4, 5]})
right
|
key | rval | |
---|---|---|
0 | foo | 4 |
1 | bar | 5 |
keyカラム(列)を基準にしてマージします。
1 | pd.merge(left, right, on='key')
|
key | lval | rval | |
---|---|---|---|
0 | foo | 1 | 4 |
1 | bar | 2 | 5 |
9.3. 追加[11]
DataFrameに行を追加するのには、DataFrame.appendメソッドを使います。
例を示す為にまずは下記のようなDataFrameとSeriesを用意します。
1 2 | df = pd.DataFrame(np.random.randn(8, 4), columns=['A', 'B', 'C', 'D'])
df
|
A | B | C | D | |
---|---|---|---|---|
0 | 1.346061 | 1.511763 | 1.627081 | -0.990582 |
1 | -0.441652 | 1.211526 | 0.268520 | 0.024580 |
2 | -1.577585 | 0.396823 | -0.105381 | -0.532532 |
3 | 1.453749 | 1.208843 | -0.080952 | -0.264610 |
4 | -0.727965 | -0.589346 | 0.339969 | -0.693205 |
5 | -0.339355 | 0.593616 | 0.884345 | 1.591431 |
6 | 0.141809 | 0.220390 | 0.435589 | 0.192451 |
7 | -0.096701 | 0.803351 | 1.715071 | -0.708758 |
1 2 | s = df.iloc[3]
s
|
A 1.453749 B 1.208843 C -0.080952 D -0.264610 Name: 3, dtype: float64
DataFrame.appendメソッドを使って、インデックスを無視してDataFrameにSeriesを追加します。[23]
1 | df.append(s, ignore_index=True)
|
A | B | C | D | |
---|---|---|---|---|
0 | 1.346061 | 1.511763 | 1.627081 | -0.990582 |
1 | -0.441652 | 1.211526 | 0.268520 | 0.024580 |
2 | -1.577585 | 0.396823 | -0.105381 | -0.532532 |
3 | 1.453749 | 1.208843 | -0.080952 | -0.264610 |
4 | -0.727965 | -0.589346 | 0.339969 | -0.693205 |
5 | -0.339355 | 0.593616 | 0.884345 | 1.591431 |
6 | 0.141809 | 0.220390 | 0.435589 | 0.192451 |
7 | -0.096701 | 0.803351 | 1.715071 | -0.708758 |
8 | 1.453749 | 1.208843 | -0.080952 | -0.264610 |
DataFrame.appendメソッドを使って、インデックスを無視せずにDataFrameにSeriesを追加します。[23]
1 | df.append(s, ignore_index=False)
|
A | B | C | D | |
---|---|---|---|---|
0 | 1.346061 | 1.511763 | 1.627081 | -0.990582 |
1 | -0.441652 | 1.211526 | 0.268520 | 0.024580 |
2 | -1.577585 | 0.396823 | -0.105381 | -0.532532 |
3 | 1.453749 | 1.208843 | -0.080952 | -0.264610 |
4 | -0.727965 | -0.589346 | 0.339969 | -0.693205 |
5 | -0.339355 | 0.593616 | 0.884345 | 1.591431 |
6 | 0.141809 | 0.220390 | 0.435589 | 0.192451 |
7 | -0.096701 | 0.803351 | 1.715071 | -0.708758 |
3 | 1.453749 | 1.208843 | -0.080952 | -0.264610 |
10. グルーピング(グループ化)[12]
pandasで言うところの「グルーピング(Group By)」とは、下記の一つ以上の手順を含む処理のことです。
- ある基準に従って、データをグループに分割すること
- 各グループに関数を個別に適用すること
- その結果を結合して1つのデータ構造にすること
例を示す為にまずは下記のようなDataFrameを用意します。
1 2 3 4 5 6 7 | df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar',
'foo', 'bar', 'foo', 'foo'],
'B' : ['one', 'one', 'two', 'three',
'two', 'two', 'one', 'three'],
'C' : np.random.randn(8),
'D' : np.random.randn(8)})
df
|
A | B | C | D | |
---|---|---|---|---|
0 | foo | one | -1.202872 | -0.055224 |
1 | bar | one | -1.814470 | 2.395985 |
2 | foo | two | 1.018601 | 1.552825 |
3 | bar | three | -0.595447 | 0.166599 |
4 | foo | two | 1.395433 | 0.047609 |
5 | bar | two | -0.392670 | -0.136473 |
6 | foo | one | 0.007207 | -0.561757 |
7 | foo | three | 1.928123 | -1.623033 |
カラム(列)「A」の値でデータをグルーピングし、その結果にGroupBy.sumメソッドを適用します。
1 | df.groupby('A').sum()
|
C | D | |
---|---|---|
A | ||
bar | -2.802588 | 2.42611 |
foo | 3.146492 | -0.63958 |
複数のカラム(列)でグルーピングすると、関数を適用した時点でマルチインデックスになります。
1 | df.groupby(['A', 'B']).sum()
|
C | D | ||
---|---|---|---|
A | B | ||
bar | one | -1.814470 | 2.395985 |
three | -0.595447 | 0.166599 | |
two | -0.392670 | -0.136473 | |
foo | one | -1.195665 | -0.616981 |
three | 1.928123 | -1.623033 | |
two | 2.414034 | 1.600434 |
11. 構成変更(リシェイプ)[13][14]
11.1. スタック
例を示す為にまずは下記のようなDataFrameを用意します。
1 2 3 4 5 | tuples = list(zip(*[['bar', 'bar', 'baz', 'baz',
'foo', 'foo', 'qux', 'qux'],
['one', 'two', 'one', 'two',
'one', 'two', 'one', 'two']]))
tuples
|
[('bar', 'one'), ('bar', 'two'), ('baz', 'one'), ('baz', 'two'), ('foo', 'one'), ('foo', 'two'), ('qux', 'one'), ('qux', 'two')]
1 2 | index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
index
|
MultiIndex(levels=[['bar', 'baz', 'foo', 'qux'], ['one', 'two']], labels=[[0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 0, 1, 0, 1, 0, 1]], names=['first', 'second'])
1 2 | df = pd.DataFrame(np.random.randn(8, 2), index=index, columns=['A', 'B'])
df
|
A | B | ||
---|---|---|---|
first | second | ||
bar | one | 0.029399 | -0.542108 |
two | 0.282696 | -0.087302 | |
baz | one | -1.575170 | 1.771208 |
two | 0.816482 | 1.100230 | |
foo | one | -0.612665 | 1.586976 |
two | 0.019234 | 0.264294 | |
qux | one | 1.074803 | 0.173520 |
two | 0.211027 | 1.357138 |
dfから下記のようにdf2を作ります。
1 2 | df2 = df[:4]
df2
|
A | B | ||
---|---|---|---|
first | second | ||
bar | one | 0.029399 | -0.542108 |
two | 0.282696 | -0.087302 | |
baz | one | -1.575170 | 1.771208 |
two | 0.816482 | 1.100230 |
DataFrame.stack メソッドは、カラム(列)をマルチインデックスの1つの階層(レベル)に"圧縮"します。
1 2 | stacked = df2.stack()
stacked
|
first second bar one A 0.029399 B -0.542108 two A 0.282696 B -0.087302 baz one A -1.575170 B 1.771208 two A 0.816482 B 1.100230 dtype: float64
インデックスを確認すると、こうなっています。
1 | stacked.index
|
MultiIndex(levels=[['bar', 'baz', 'foo', 'qux'], ['one', 'two'], ['A', 'B']], labels=[[0, 0, 0, 0, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 1, 1], [0, 1, 0, 1, 0, 1, 0, 1]], names=['first', 'second', None])
マルチインデックスを持つ"スタックされた"DataFrameやSeriesに対して、DataFrame.unstack メソッド(DataFrame.stackメソッドとは逆の操作)をすると、こうなります。デフォルトでは、最後の階層(レベル)をカラム(列)にします。
1 | stacked.unstack()
|
A | B | ||
---|---|---|---|
first | second | ||
bar | one | 0.029399 | -0.542108 |
two | 0.282696 | -0.087302 | |
baz | one | -1.575170 | 1.771208 |
two | 0.816482 | 1.100230 |
階層(レベル)を指定するとこうなります。
1 | stacked.unstack(1)
|
second | one | two | |
---|---|---|---|
first | |||
bar | A | 0.029399 | 0.282696 |
B | -0.542108 | -0.087302 | |
baz | A | -1.575170 | 0.816482 |
B | 1.771208 | 1.100230 |
1 | stacked.unstack(0)
|
first | bar | baz | |
---|---|---|---|
second | |||
one | A | 0.029399 | -1.575170 |
B | -0.542108 | 1.771208 | |
two | A | 0.282696 | 0.816482 |
B | -0.087302 | 1.100230 |
11.2. ピボットテーブル[15]
例を示す為にまずは下記のようなDataFrameを用意します。
1 2 3 4 5 6 | df = pd.DataFrame({'A' : ['one', 'one', 'two', 'three'] * 3,
'B' : ['A', 'B', 'C'] * 4,
'C' : ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 2,
'D' : np.random.randn(12),
'E' : np.random.randn(12)})
df
|
A | B | C | D | E | |
---|---|---|---|---|---|
0 | one | A | foo | 1.418757 | -0.179666 |
1 | one | B | foo | -1.879024 | 1.291836 |
2 | two | C | foo | 0.536826 | -0.009614 |
3 | three | A | bar | 1.006160 | 0.392149 |
4 | one | B | bar | -0.029716 | 0.264599 |
5 | one | C | bar | -1.146178 | -0.057409 |
6 | two | A | foo | 0.100900 | -1.425638 |
7 | three | B | foo | -1.035018 | 1.024098 |
8 | one | C | foo | 0.314665 | -0.106062 |
9 | one | A | bar | -0.773723 | 1.824375 |
10 | two | B | bar | -1.170653 | 0.595974 |
11 | three | C | bar | 0.648740 | 1.167115 |
所謂ピボットテーブルを作るのには、pivot_table関数を使います。
この例では、下記のようにカラム(列)名を指定しています。
- カラム(列)「A」と「B」をインデックスに。
- カラム(列)「C」の値を、新たなカラムに。
- カラム(列)「D」の値を、データとして各値に。
1 | pd.pivot_table(df, values='D', index=['A', 'B'], columns=['C'])
|
C | bar | foo | |
---|---|---|---|
A | B | ||
one | A | -0.773723 | 1.418757 |
B | -0.029716 | -1.879024 | |
C | -1.146178 | 0.314665 | |
three | A | 1.006160 | NaN |
B | NaN | -1.035018 | |
C | 0.648740 | NaN | |
two | A | NaN | 0.100900 |
B | -1.170653 | NaN | |
C | NaN | 0.536826 |
以下、記述中。
12. 日時の処理[16]
pandasには、シンプルで強力で且つ効率的な、時間の頻度変換の機能を備えています。時間の頻度変換とは例えば、1秒毎のデータを5分毎のデータにする、というような変換のことです。
例を示す為に、date_range関数を使って下記のようなDatetimeIndexを作ります。これは2017/1/1の0時0分0秒から1秒毎に100個(つまり99秒後まで)の要素を持ちます。
1 2 | rng = pd.date_range('1/1/2017', periods=100, freq='S')
rng
|
DatetimeIndex(['2017-01-01 00:00:00', '2017-01-01 00:00:01', '2017-01-01 00:00:02', '2017-01-01 00:00:03', '2017-01-01 00:00:04', '2017-01-01 00:00:05', '2017-01-01 00:00:06', '2017-01-01 00:00:07', '2017-01-01 00:00:08', '2017-01-01 00:00:09', '2017-01-01 00:00:10', '2017-01-01 00:00:11', '2017-01-01 00:00:12', '2017-01-01 00:00:13', '2017-01-01 00:00:14', '2017-01-01 00:00:15', '2017-01-01 00:00:16', '2017-01-01 00:00:17', '2017-01-01 00:00:18', '2017-01-01 00:00:19', '2017-01-01 00:00:20', '2017-01-01 00:00:21', '2017-01-01 00:00:22', '2017-01-01 00:00:23', '2017-01-01 00:00:24', '2017-01-01 00:00:25', '2017-01-01 00:00:26', '2017-01-01 00:00:27', '2017-01-01 00:00:28', '2017-01-01 00:00:29', '2017-01-01 00:00:30', '2017-01-01 00:00:31', '2017-01-01 00:00:32', '2017-01-01 00:00:33', '2017-01-01 00:00:34', '2017-01-01 00:00:35', '2017-01-01 00:00:36', '2017-01-01 00:00:37', '2017-01-01 00:00:38', '2017-01-01 00:00:39', '2017-01-01 00:00:40', '2017-01-01 00:00:41', '2017-01-01 00:00:42', '2017-01-01 00:00:43', '2017-01-01 00:00:44', '2017-01-01 00:00:45', '2017-01-01 00:00:46', '2017-01-01 00:00:47', '2017-01-01 00:00:48', '2017-01-01 00:00:49', '2017-01-01 00:00:50', '2017-01-01 00:00:51', '2017-01-01 00:00:52', '2017-01-01 00:00:53', '2017-01-01 00:00:54', '2017-01-01 00:00:55', '2017-01-01 00:00:56', '2017-01-01 00:00:57', '2017-01-01 00:00:58', '2017-01-01 00:00:59', '2017-01-01 00:01:00', '2017-01-01 00:01:01', '2017-01-01 00:01:02', '2017-01-01 00:01:03', '2017-01-01 00:01:04', '2017-01-01 00:01:05', '2017-01-01 00:01:06', '2017-01-01 00:01:07', '2017-01-01 00:01:08', '2017-01-01 00:01:09', '2017-01-01 00:01:10', '2017-01-01 00:01:11', '2017-01-01 00:01:12', '2017-01-01 00:01:13', '2017-01-01 00:01:14', '2017-01-01 00:01:15', '2017-01-01 00:01:16', '2017-01-01 00:01:17', '2017-01-01 00:01:18', '2017-01-01 00:01:19', '2017-01-01 00:01:20', '2017-01-01 00:01:21', '2017-01-01 00:01:22', '2017-01-01 00:01:23', '2017-01-01 00:01:24', '2017-01-01 00:01:25', '2017-01-01 00:01:26', '2017-01-01 00:01:27', '2017-01-01 00:01:28', '2017-01-01 00:01:29', '2017-01-01 00:01:30', '2017-01-01 00:01:31', '2017-01-01 00:01:32', '2017-01-01 00:01:33', '2017-01-01 00:01:34', '2017-01-01 00:01:35', '2017-01-01 00:01:36', '2017-01-01 00:01:37', '2017-01-01 00:01:38', '2017-01-01 00:01:39'], dtype='datetime64[ns]', freq='S')
それをインデックスに持つSeriesを作ります。値は、0から500までのランダムな整数です。
1 2 | ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)
ts
|
2017-01-01 00:00:00 410 2017-01-01 00:00:01 166 2017-01-01 00:00:02 232 2017-01-01 00:00:03 256 2017-01-01 00:00:04 413 2017-01-01 00:00:05 410 2017-01-01 00:00:06 412 ... 2017-01-01 00:01:33 133 2017-01-01 00:01:34 366 2017-01-01 00:01:35 134 2017-01-01 00:01:36 77 2017-01-01 00:01:37 377 2017-01-01 00:01:38 86 2017-01-01 00:01:39 439 Freq: S, Length: 100, dtype: int64
Series.resampleメソッドで頻度を5分毎に変換します。(全部で1分39秒までしかないので、1行にまとまってしまいます)
1 | ts.resample('5Min').sum()
|
2017-01-01 25083 Freq: 5T, dtype: int64
頻度を5秒毎に変換します。
1 | ts.resample('5s').sum()
|
2017-01-01 00:00:00 1477 2017-01-01 00:00:05 1657 2017-01-01 00:00:10 1299 2017-01-01 00:00:15 1242 2017-01-01 00:00:20 1451 2017-01-01 00:00:25 1359 2017-01-01 00:00:30 1250 ... 2017-01-01 00:01:05 1334 2017-01-01 00:01:10 1093 2017-01-01 00:01:15 1297 2017-01-01 00:01:20 1308 2017-01-01 00:01:25 1407 2017-01-01 00:01:30 773 2017-01-01 00:01:35 1113 Freq: 5S, Length: 20, dtype: int64
頻度を30秒毎に変換します。
1 | ts.resample('30s').sum()
|
2017-01-01 00:00:00 8485 2017-01-01 00:00:30 7098 2017-01-01 00:01:00 7614 2017-01-01 00:01:30 1886 Freq: 30S, dtype: int64
頻度を1日毎に変換します。1行にまとまってしまうところは5分毎に変換した場合と同じですが、「Freq」(頻度)の表記が「D」になっています。
1 | ts.resample('1d').sum()
|
2017-01-01 25083 Freq: D, dtype: int64
タイムゾーンの扱い方の例を示す為に、date_range関数を使って下記のようなDatetimeIndexを作ります。
1 2 | rng = pd.date_range('3/6/2017 00:00', periods=5, freq='D')
rng
|
DatetimeIndex(['2017-03-06', '2017-03-07', '2017-03-08', '2017-03-09', '2017-03-10'], dtype='datetime64[ns]', freq='D')
それをインデックスに持つSeriesを作ります。
1 2 | ts = pd.Series(np.random.randn(len(rng)), rng)
ts
|
2017-03-06 0.464000 2017-03-07 0.227371 2017-03-08 -0.496922 2017-03-09 0.306389 2017-03-10 -2.290613 Freq: D, dtype: float64
タイムゾーンをUTC(協定世界時)に変換します。
1 2 | ts_utc = ts.tz_localize('UTC')
ts_utc
|
2017-03-06 00:00:00+00:00 0.464000 2017-03-07 00:00:00+00:00 0.227371 2017-03-08 00:00:00+00:00 -0.496922 2017-03-09 00:00:00+00:00 0.306389 2017-03-10 00:00:00+00:00 -2.290613 Freq: D, dtype: float64
タイムゾーンをUS/Eastern(アメリカ東部標準時)に変更します。
1 | ts_utc.tz_convert('US/Eastern')
|
2017-03-05 19:00:00-05:00 0.464000 2017-03-06 19:00:00-05:00 0.227371 2017-03-07 19:00:00-05:00 -0.496922 2017-03-08 19:00:00-05:00 0.306389 2017-03-09 19:00:00-05:00 -2.290613 Freq: D, dtype: float64
タイムゾーンを日本に変更します。
1 | ts_utc.tz_convert('Japan')
|
2017-03-06 09:00:00+09:00 0.464000 2017-03-07 09:00:00+09:00 0.227371 2017-03-08 09:00:00+09:00 -0.496922 2017-03-09 09:00:00+09:00 0.306389 2017-03-10 09:00:00+09:00 -2.290613 Freq: D, dtype: float64
時刻と期間(time span)の変換の例を示す為に、date_range関数を使って下記のようなDatetimeIndexを作ります。
1 2 | rng = pd.date_range('1/1/2017', periods=5, freq='M')
rng
|
DatetimeIndex(['2017-01-31', '2017-02-28', '2017-03-31', '2017-04-30', '2017-05-31'], dtype='datetime64[ns]', freq='M')
それをインデックスに持つSeriesを作ります。
1 2 | ts = pd.Series(np.random.randn(len(rng)), index=rng)
ts
|
2017-01-31 -1.134623 2017-02-28 -1.561819 2017-03-31 -0.260838 2017-04-30 0.281957 2017-05-31 1.523962 Freq: M, dtype: float64
Series.to_periodメソッドで時刻を期間に変換します。
1 2 | ps = ts.to_period()
ps
|
2017-01 -1.134623 2017-02 -1.561819 2017-03 -0.260838 2017-04 0.281957 2017-05 1.523962 Freq: M, dtype: float64
元のtsのインデックスはDatetimeIndexであるのに対し、
1 | ts.index
|
DatetimeIndex(['2017-01-31', '2017-02-28', '2017-03-31', '2017-04-30', '2017-05-31'], dtype='datetime64[ns]', freq='M')
psのインデックスはPeriodIndexです。
1 | ps.index
|
PeriodIndex(['2017-01', '2017-02', '2017-03', '2017-04', '2017-05'], dtype='period[M]', freq='M')
Series.to_timestampメソッドで期間から時刻に戻ります。
1 | ps.to_timestamp()
|
2017-01-01 -1.134623 2017-02-01 -1.561819 2017-03-01 -0.260838 2017-04-01 0.281957 2017-05-01 1.523962 Freq: MS, dtype: float64
1 | ps.to_timestamp().index
|
DatetimeIndex(['2017-01-01', '2017-02-01', '2017-03-01', '2017-04-01', '2017-05-01'], dtype='datetime64[ns]', freq='MS')
時刻と期間の変換の、もう少し複雑な例を見てみます。下記の例では、「11月を年度末とした時の四半期(Q)」(期間)から、「その四半期の直後の月始めの9時」(時刻)に変換しています。
まず、period_range関数で1990年の第1四半期(第1Q)から2000年の第4四半期(第4Q)までのPeriodIndexを作ります。
1 2 | prng = pd.period_range('1990Q1', '2000Q4', freq='Q-NOV')
prng
|
PeriodIndex(['1990Q1', '1990Q2', '1990Q3', '1990Q4', '1991Q1', '1991Q2', '1991Q3', '1991Q4', '1992Q1', '1992Q2', '1992Q3', '1992Q4', '1993Q1', '1993Q2', '1993Q3', '1993Q4', '1994Q1', '1994Q2', '1994Q3', '1994Q4', '1995Q1', '1995Q2', '1995Q3', '1995Q4', '1996Q1', '1996Q2', '1996Q3', '1996Q4', '1997Q1', '1997Q2', '1997Q3', '1997Q4', '1998Q1', '1998Q2', '1998Q3', '1998Q4', '1999Q1', '1999Q2', '1999Q3', '1999Q4', '2000Q1', '2000Q2', '2000Q3', '2000Q4'], dtype='period[Q-NOV]', freq='Q-NOV')
それをインデックスに持つSeriesを作ります。
1 2 | ts = pd.Series(np.random.randn(len(prng)), prng)
ts
|
1990Q1 -0.902937 1990Q2 0.068159 1990Q3 -0.057873 1990Q4 -0.368204 1991Q1 -1.144073 1991Q2 0.861209 1991Q3 0.800193 ... 1999Q2 -0.928797 1999Q3 -0.308853 1999Q4 -0.681087 2000Q1 0.377953 2000Q2 0.493672 2000Q3 -2.461467 2000Q4 -1.553902 Freq: Q-NOV, Length: 44, dtype: float64
PeriodIndex.asfreqメソッドを組み合わせて、表示日時や頻度を変更します。(複雑なので、この後ひとつずつ分解して説明します)
1 | (prng.asfreq('M', 'e') + 1).asfreq('H', 's') + 9
|
PeriodIndex(['1990-03-01 09:00', '1990-06-01 09:00', '1990-09-01 09:00', '1990-12-01 09:00', '1991-03-01 09:00', '1991-06-01 09:00', '1991-09-01 09:00', '1991-12-01 09:00', '1992-03-01 09:00', '1992-06-01 09:00', '1992-09-01 09:00', '1992-12-01 09:00', '1993-03-01 09:00', '1993-06-01 09:00', '1993-09-01 09:00', '1993-12-01 09:00', '1994-03-01 09:00', '1994-06-01 09:00', '1994-09-01 09:00', '1994-12-01 09:00', '1995-03-01 09:00', '1995-06-01 09:00', '1995-09-01 09:00', '1995-12-01 09:00', '1996-03-01 09:00', '1996-06-01 09:00', '1996-09-01 09:00', '1996-12-01 09:00', '1997-03-01 09:00', '1997-06-01 09:00', '1997-09-01 09:00', '1997-12-01 09:00', '1998-03-01 09:00', '1998-06-01 09:00', '1998-09-01 09:00', '1998-12-01 09:00', '1999-03-01 09:00', '1999-06-01 09:00', '1999-09-01 09:00', '1999-12-01 09:00', '2000-03-01 09:00', '2000-06-01 09:00', '2000-09-01 09:00', '2000-12-01 09:00'], dtype='period[H]', freq='H')
まずPeriodIndex.asfreqメソッドで、頻度を月毎に、四半期(Q)の終了月に揃えます。
1 | prng.asfreq('M', 'e')
|
PeriodIndex(['1990-02', '1990-05', '1990-08', '1990-11', '1991-02', '1991-05', '1991-08', '1991-11', '1992-02', '1992-05', '1992-08', '1992-11', '1993-02', '1993-05', '1993-08', '1993-11', '1994-02', '1994-05', '1994-08', '1994-11', '1995-02', '1995-05', '1995-08', '1995-11', '1996-02', '1996-05', '1996-08', '1996-11', '1997-02', '1997-05', '1997-08', '1997-11', '1998-02', '1998-05', '1998-08', '1998-11', '1999-02', '1999-05', '1999-08', '1999-11', '2000-02', '2000-05', '2000-08', '2000-11'], dtype='period[M]', freq='M')
そこに1を足すことで、月をひと月進めます。
1 | prng.asfreq('M', 'e') + 1
|
PeriodIndex(['1990-03', '1990-06', '1990-09', '1990-12', '1991-03', '1991-06', '1991-09', '1991-12', '1992-03', '1992-06', '1992-09', '1992-12', '1993-03', '1993-06', '1993-09', '1993-12', '1994-03', '1994-06', '1994-09', '1994-12', '1995-03', '1995-06', '1995-09', '1995-12', '1996-03', '1996-06', '1996-09', '1996-12', '1997-03', '1997-06', '1997-09', '1997-12', '1998-03', '1998-06', '1998-09', '1998-12', '1999-03', '1999-06', '1999-09', '1999-12', '2000-03', '2000-06', '2000-09', '2000-12'], dtype='period[M]', freq='M')
更にPeriodIndex.asfreqメソッドで、頻度を時間毎にして、1日の0時に揃えます。
1 | (prng.asfreq('M', 'e') + 1).asfreq('H', 's')
|
PeriodIndex(['1990-03-01 00:00', '1990-06-01 00:00', '1990-09-01 00:00', '1990-12-01 00:00', '1991-03-01 00:00', '1991-06-01 00:00', '1991-09-01 00:00', '1991-12-01 00:00', '1992-03-01 00:00', '1992-06-01 00:00', '1992-09-01 00:00', '1992-12-01 00:00', '1993-03-01 00:00', '1993-06-01 00:00', '1993-09-01 00:00', '1993-12-01 00:00', '1994-03-01 00:00', '1994-06-01 00:00', '1994-09-01 00:00', '1994-12-01 00:00', '1995-03-01 00:00', '1995-06-01 00:00', '1995-09-01 00:00', '1995-12-01 00:00', '1996-03-01 00:00', '1996-06-01 00:00', '1996-09-01 00:00', '1996-12-01 00:00', '1997-03-01 00:00', '1997-06-01 00:00', '1997-09-01 00:00', '1997-12-01 00:00', '1998-03-01 00:00', '1998-06-01 00:00', '1998-09-01 00:00', '1998-12-01 00:00', '1999-03-01 00:00', '1999-06-01 00:00', '1999-09-01 00:00', '1999-12-01 00:00', '2000-03-01 00:00', '2000-06-01 00:00', '2000-09-01 00:00', '2000-12-01 00:00'], dtype='period[H]', freq='H')
最後に9を足して、時間を9時に揃えます。
1 | (prng.asfreq('M', 'e') + 1).asfreq('H', 's') + 9
|
PeriodIndex(['1990-03-01 09:00', '1990-06-01 09:00', '1990-09-01 09:00', '1990-12-01 09:00', '1991-03-01 09:00', '1991-06-01 09:00', '1991-09-01 09:00', '1991-12-01 09:00', '1992-03-01 09:00', '1992-06-01 09:00', '1992-09-01 09:00', '1992-12-01 09:00', '1993-03-01 09:00', '1993-06-01 09:00', '1993-09-01 09:00', '1993-12-01 09:00', '1994-03-01 09:00', '1994-06-01 09:00', '1994-09-01 09:00', '1994-12-01 09:00', '1995-03-01 09:00', '1995-06-01 09:00', '1995-09-01 09:00', '1995-12-01 09:00', '1996-03-01 09:00', '1996-06-01 09:00', '1996-09-01 09:00', '1996-12-01 09:00', '1997-03-01 09:00', '1997-06-01 09:00', '1997-09-01 09:00', '1997-12-01 09:00', '1998-03-01 09:00', '1998-06-01 09:00', '1998-09-01 09:00', '1998-12-01 09:00', '1999-03-01 09:00', '1999-06-01 09:00', '1999-09-01 09:00', '1999-12-01 09:00', '2000-03-01 09:00', '2000-06-01 09:00', '2000-09-01 09:00', '2000-12-01 09:00'], dtype='period[H]', freq='H')
これをtsのインデックスにセットすると、こうなります。
1 2 | ts.index = (prng.asfreq('M', 'e') + 1).asfreq('H', 's') + 9
ts.head()
|
1990-03-01 09:00 -0.902937 1990-06-01 09:00 0.068159 1990-09-01 09:00 -0.057873 1990-12-01 09:00 -0.368204 1991-03-01 09:00 -1.144073 Freq: H, dtype: float64
13. カテゴリ型[17]
pandasでは、DataFrameにカテゴリ型のデータを含めることができます。
例を示す為にまずは下記のようなDataFrameを用意します。AからEの成績データを、そのまま文字列で表現しています。
1 2 | df = pd.DataFrame({'id':[1,2,3,4,5,6], 'raw_grade':['a', 'b', 'b', 'a', 'a', 'e']})
df
|
id | raw_grade | |
---|---|---|
0 | 1 | a |
1 | 2 | b |
2 | 3 | b |
3 | 4 | a |
4 | 5 | a |
5 | 6 | e |
「raw_grade」カラム(列)の成績をSeries.astypeメソッドでカテゴリ型に変換して、「grade」カラム(列)に格納します。[24]dtypeが「category」になっていることが分かります。
1 2 | df['grade'] = df['raw_grade'].astype('category')
df['grade']
|
0 a 1 b 2 b 3 a 4 a 5 e Name: grade, dtype: category Categories (3, object): [a, b, e]
DataFrame全体を確認します。
1 | df
|
id | raw_grade | grade | |
---|---|---|---|
0 | 1 | a | a |
1 | 2 | b | b |
2 | 3 | b | b |
3 | 4 | a | a |
4 | 5 | a | a |
5 | 6 | e | e |
Series.cat.categoriesプロパティでカテゴリの値を取得したり、セットしたりできます。
1 | df['grade'].cat.categories
|
Index(['a', 'b', 'e'], dtype='object')
ここでは、それぞれA、B、Eをもっと分かり易く「very good」「good」「very bad」に変更します。
1 2 | df['grade'].cat.categories = ['very good', 'good', 'very bad']
df['grade'].cat.categories
|
Index(['very good', 'good', 'very bad'], dtype='object')
「grade」カラム(列)を確認します。
1 | df['grade']
|
0 very good 1 good 2 good 3 very good 4 very good 5 very bad Name: grade, dtype: category Categories (3, object): [very good, good, very bad]
Series.cat.set_categoriesメソッドを使えば、そのSeriesに存在しない値も含めてカテゴリを再設定できます。
1 | df['grade'].cat.set_categories(['very bad', 'bad', 'medium', 'good', 'very good'])
|
0 very good 1 good 2 good 3 very good 4 very good 5 very bad Name: grade, dtype: category Categories (5, object): [very bad, bad, medium, good, very good]
Series.cat.set_categoriesは、初期設定では新しいSeriesを返すので、「grade」カラム(列)を置き換える場合は、例えば下記のように代入し直します。
1 2 | df['grade'] = df['grade'].cat.set_categories(['very bad', 'bad', 'medium', 'good', 'very good'])
df['grade']
|
0 very good 1 good 2 good 3 very good 4 very good 5 very bad Name: grade, dtype: category Categories (5, object): [very bad, bad, medium, good, very good]
この時点のDataFrameを確認します。
1 | df
|
id | raw_grade | grade | |
---|---|---|---|
0 | 1 | a | very good |
1 | 2 | b | good |
2 | 3 | b | good |
3 | 4 | a | very good |
4 | 5 | a | very good |
5 | 6 | e | very bad |
カテゴリ型データをDataFrame.sort_valuesメソッドで並び替えると、文字の順序ではなく、カテゴリの順序で並び替えられます。
1 | df.sort_values(by='grade')
|
id | raw_grade | grade | |
---|---|---|---|
5 | 6 | e | very bad |
1 | 2 | b | good |
2 | 3 | b | good |
0 | 1 | a | very good |
3 | 4 | a | very good |
4 | 5 | a | very good |
DataFrame.groupbyでグループ化した場合は、空のグループも表示してくれます。
1 | df.groupby('grade').size()
|
grade very bad 1 bad 0 medium 0 good 2 very good 3 dtype: int64
Series.value_countsでも、0個の要素を表示してくれます。
1 | df['grade'].value_counts()
|
very good 3 good 2 very bad 1 medium 0 bad 0 Name: grade, dtype: int64
14. プロット[18]
データをグラフとしてプロットするには、Series.plotメソッドやDataFrame.plotメソッドを使います。
例を示す為に、2000/1/1から1000日分のインデックスとランダムな値を持ったSeriesを作ります。
1 2 | ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))
ts
|
2000-01-01 2.015523 2000-01-02 -1.833722 2000-01-03 1.771740 2000-01-04 -0.670027 2000-01-05 0.049307 2000-01-06 -0.521493 2000-01-07 -3.201750 ... 2002-09-20 -1.187785 2002-09-21 -0.183798 2002-09-22 -1.211230 2002-09-23 -0.856833 2002-09-24 -0.600575 2002-09-25 0.361428 2002-09-26 0.887304 Freq: D, Length: 1000, dtype: float64
Series.cumsumメソッドで累積和を計算して、置き換えます。
1 2 | ts = ts.cumsum()
ts
|
2000-01-01 2.015523 2000-01-02 0.181801 2000-01-03 1.953541 2000-01-04 1.283514 2000-01-05 1.332821 2000-01-06 0.811328 2000-01-07 -2.390423 ... 2002-09-20 -12.233834 2002-09-21 -12.417632 2002-09-22 -13.628862 2002-09-23 -14.485695 2002-09-24 -15.086270 2002-09-25 -14.724842 2002-09-26 -13.837538 Freq: D, Length: 1000, dtype: float64
Series.plotメソッドでグラフを描画します。グラフ描画にはmatplotlibが使用されます。グラフがどこに表示されるかは、環境・設定によります。
1 | ts.plot()
|
<matplotlib.axes._subplots.AxesSubplot at 0x10dea2048>

DataFrameの場合の例も示します。例を示す為に、先ほどのSeriesをインデックスに持ち、A、B、C、Dの4つのカラム(列)を持ったDataFrameを作成します。
1 2 | df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index, columns=['A', 'B', 'C', 'D'])
df
|
A | B | C | D | |
---|---|---|---|---|
2000-01-01 | 0.266457 | -0.399641 | -0.219582 | 1.186860 |
2000-01-02 | -1.437189 | 0.053768 | 1.872644 | -1.469813 |
2000-01-03 | -0.564201 | 0.876341 | 0.407749 | -0.232583 |
2000-01-04 | 0.179812 | 0.922152 | -1.820952 | -0.641360 |
2000-01-05 | 2.133239 | -0.941248 | -0.136307 | -1.271305 |
2000-01-06 | -0.099774 | -0.061438 | -0.845172 | 0.465793 |
2000-01-07 | 0.756995 | -0.541690 | -0.802241 | 0.877657 |
... | ... | ... | ... | ... |
2002-09-20 | 1.279409 | -0.395335 | -0.451316 | 0.839783 |
2002-09-21 | 0.238172 | 0.426073 | 1.483501 | 2.600168 |
2002-09-22 | 1.405015 | 0.241867 | 1.730183 | 0.453633 |
2002-09-23 | -0.573198 | -0.295592 | 0.169647 | -0.849301 |
2002-09-24 | -0.343498 | -0.559274 | 0.113176 | -0.412847 |
2002-09-25 | -0.313962 | -0.140192 | 0.452837 | -0.347033 |
2002-09-26 | -1.640754 | -1.190330 | 0.717777 | -0.389192 |
1000 rows × 4 columns
DataFrame.cumsumメソッドで累積和を計算して、置き換えます。
1 2 | df = df.cumsum()
df
|
A | B | C | D | |
---|---|---|---|---|
2000-01-01 | 0.266457 | -0.399641 | -0.219582 | 1.186860 |
2000-01-02 | -1.170732 | -0.345873 | 1.653061 | -0.282953 |
2000-01-03 | -1.734933 | 0.530468 | 2.060811 | -0.515536 |
2000-01-04 | -1.555121 | 1.452620 | 0.239859 | -1.156896 |
2000-01-05 | 0.578117 | 0.511371 | 0.103552 | -2.428202 |
2000-01-06 | 0.478344 | 0.449933 | -0.741620 | -1.962409 |
2000-01-07 | 1.235339 | -0.091757 | -1.543861 | -1.084753 |
... | ... | ... | ... | ... |
2002-09-20 | -10.628548 | -9.153563 | -7.883146 | 28.313940 |
2002-09-21 | -10.390377 | -8.727491 | -6.399645 | 30.914107 |
2002-09-22 | -8.985362 | -8.485624 | -4.669462 | 31.367740 |
2002-09-23 | -9.558560 | -8.781216 | -4.499815 | 30.518439 |
2002-09-24 | -9.902058 | -9.340490 | -4.386639 | 30.105593 |
2002-09-25 | -10.216020 | -9.480682 | -3.933802 | 29.758560 |
2002-09-26 | -11.856774 | -10.671012 | -3.216025 | 29.369368 |
1000 rows × 4 columns
matplotlib.pyplot.figureメソッドで、新規Figureオブジェクトを作成し(matplotlibの使い方の詳細はここでは割愛します)、DataFrame.plotメソッドでグラフを描画します。
また、matplotlib.pyplot.legendメソッドで、凡例を表示することを明示的に支持しています。
1 2 3 | plt.figure()
df.plot()
plt.legend(loc='best')
|
<matplotlib.legend.Legend at 0x110c36278>
<matplotlib.figure.Figure at 0x110c9cf60>

Figureの作成や凡例表示の指示は、省略可能です。
1 | df.plot()
|
<matplotlib.axes._subplots.AxesSubplot at 0x110e97a58>

15. データ入出力
各種形式のデータからDataFrameを生成したり、DataFrameから各種形式のデータを作成する方法について紹介します。
15.1. CSV[24]
処理を理解し易いように、まずは元のDataFrameを確認しておきます。
1 | df
|
A | B | C | D | |
---|---|---|---|---|
2000-01-01 | 0.266457 | -0.399641 | -0.219582 | 1.186860 |
2000-01-02 | -1.170732 | -0.345873 | 1.653061 | -0.282953 |
2000-01-03 | -1.734933 | 0.530468 | 2.060811 | -0.515536 |
2000-01-04 | -1.555121 | 1.452620 | 0.239859 | -1.156896 |
2000-01-05 | 0.578117 | 0.511371 | 0.103552 | -2.428202 |
2000-01-06 | 0.478344 | 0.449933 | -0.741620 | -1.962409 |
2000-01-07 | 1.235339 | -0.091757 | -1.543861 | -1.084753 |
... | ... | ... | ... | ... |
2002-09-20 | -10.628548 | -9.153563 | -7.883146 | 28.313940 |
2002-09-21 | -10.390377 | -8.727491 | -6.399645 | 30.914107 |
2002-09-22 | -8.985362 | -8.485624 | -4.669462 | 31.367740 |
2002-09-23 | -9.558560 | -8.781216 | -4.499815 | 30.518439 |
2002-09-24 | -9.902058 | -9.340490 | -4.386639 | 30.105593 |
2002-09-25 | -10.216020 | -9.480682 | -3.933802 | 29.758560 |
2002-09-26 | -11.856774 | -10.671012 | -3.216025 | 29.369368 |
1000 rows × 4 columns
15.1.2. 入力[20][25][27][26]
read_csv関数を使います。
1 | pd.read_csv('foo.csv')
|
Unnamed: 0 | A | B | C | D | |
---|---|---|---|---|---|
0 | 2000-01-01 | 0.266457 | -0.399641 | -0.219582 | 1.186860 |
1 | 2000-01-02 | -1.170732 | -0.345873 | 1.653061 | -0.282953 |
2 | 2000-01-03 | -1.734933 | 0.530468 | 2.060811 | -0.515536 |
3 | 2000-01-04 | -1.555121 | 1.452620 | 0.239859 | -1.156896 |
4 | 2000-01-05 | 0.578117 | 0.511371 | 0.103552 | -2.428202 |
5 | 2000-01-06 | 0.478344 | 0.449933 | -0.741620 | -1.962409 |
6 | 2000-01-07 | 1.235339 | -0.091757 | -1.543861 | -1.084753 |
... | ... | ... | ... | ... | ... |
993 | 2002-09-20 | -10.628548 | -9.153563 | -7.883146 | 28.313940 |
994 | 2002-09-21 | -10.390377 | -8.727491 | -6.399645 | 30.914107 |
995 | 2002-09-22 | -8.985362 | -8.485624 | -4.669462 | 31.367740 |
996 | 2002-09-23 | -9.558560 | -8.781216 | -4.499815 | 30.518439 |
997 | 2002-09-24 | -9.902058 | -9.340490 | -4.386639 | 30.105593 |
998 | 2002-09-25 | -10.216020 | -9.480682 | -3.933802 | 29.758560 |
999 | 2002-09-26 | -11.856774 | -10.671012 | -3.216025 | 29.369368 |
1000 rows × 5 columns
15.2. HDF5[21]
処理を理解し易いように、まずは元のDataFrameを確認しておきます。
1 | df
|
A | B | C | D | |
---|---|---|---|---|
2000-01-01 | 0.266457 | -0.399641 | -0.219582 | 1.186860 |
2000-01-02 | -1.170732 | -0.345873 | 1.653061 | -0.282953 |
2000-01-03 | -1.734933 | 0.530468 | 2.060811 | -0.515536 |
2000-01-04 | -1.555121 | 1.452620 | 0.239859 | -1.156896 |
2000-01-05 | 0.578117 | 0.511371 | 0.103552 | -2.428202 |
2000-01-06 | 0.478344 | 0.449933 | -0.741620 | -1.962409 |
2000-01-07 | 1.235339 | -0.091757 | -1.543861 | -1.084753 |
... | ... | ... | ... | ... |
2002-09-20 | -10.628548 | -9.153563 | -7.883146 | 28.313940 |
2002-09-21 | -10.390377 | -8.727491 | -6.399645 | 30.914107 |
2002-09-22 | -8.985362 | -8.485624 | -4.669462 | 31.367740 |
2002-09-23 | -9.558560 | -8.781216 | -4.499815 | 30.518439 |
2002-09-24 | -9.902058 | -9.340490 | -4.386639 | 30.105593 |
2002-09-25 | -10.216020 | -9.480682 | -3.933802 | 29.758560 |
2002-09-26 | -11.856774 | -10.671012 | -3.216025 | 29.369368 |
1000 rows × 4 columns
15.2.2. 入力
read_hdf関数を使います。
1 | pd.read_hdf('foo.h5', 'df')
|
A | B | C | D | |
---|---|---|---|---|
2000-01-01 | 0.266457 | -0.399641 | -0.219582 | 1.186860 |
2000-01-02 | -1.170732 | -0.345873 | 1.653061 | -0.282953 |
2000-01-03 | -1.734933 | 0.530468 | 2.060811 | -0.515536 |
2000-01-04 | -1.555121 | 1.452620 | 0.239859 | -1.156896 |
2000-01-05 | 0.578117 | 0.511371 | 0.103552 | -2.428202 |
2000-01-06 | 0.478344 | 0.449933 | -0.741620 | -1.962409 |
2000-01-07 | 1.235339 | -0.091757 | -1.543861 | -1.084753 |
... | ... | ... | ... | ... |
2002-09-20 | -10.628548 | -9.153563 | -7.883146 | 28.313940 |
2002-09-21 | -10.390377 | -8.727491 | -6.399645 | 30.914107 |
2002-09-22 | -8.985362 | -8.485624 | -4.669462 | 31.367740 |
2002-09-23 | -9.558560 | -8.781216 | -4.499815 | 30.518439 |
2002-09-24 | -9.902058 | -9.340490 | -4.386639 | 30.105593 |
2002-09-25 | -10.216020 | -9.480682 | -3.933802 | 29.758560 |
2002-09-26 | -11.856774 | -10.671012 | -3.216025 | 29.369368 |
1000 rows × 4 columns
15.3. Excel[22]
処理を理解し易いように、まずは元のDataFrameを確認しておきます。
1 | df
|
A | B | C | D | |
---|---|---|---|---|
2000-01-01 | 0.266457 | -0.399641 | -0.219582 | 1.186860 |
2000-01-02 | -1.170732 | -0.345873 | 1.653061 | -0.282953 |
2000-01-03 | -1.734933 | 0.530468 | 2.060811 | -0.515536 |
2000-01-04 | -1.555121 | 1.452620 | 0.239859 | -1.156896 |
2000-01-05 | 0.578117 | 0.511371 | 0.103552 | -2.428202 |
2000-01-06 | 0.478344 | 0.449933 | -0.741620 | -1.962409 |
2000-01-07 | 1.235339 | -0.091757 | -1.543861 | -1.084753 |
... | ... | ... | ... | ... |
2002-09-20 | -10.628548 | -9.153563 | -7.883146 | 28.313940 |
2002-09-21 | -10.390377 | -8.727491 | -6.399645 | 30.914107 |
2002-09-22 | -8.985362 | -8.485624 | -4.669462 | 31.367740 |
2002-09-23 | -9.558560 | -8.781216 | -4.499815 | 30.518439 |
2002-09-24 | -9.902058 | -9.340490 | -4.386639 | 30.105593 |
2002-09-25 | -10.216020 | -9.480682 | -3.933802 | 29.758560 |
2002-09-26 | -11.856774 | -10.671012 | -3.216025 | 29.369368 |
1000 rows × 4 columns
15.3.2. 入力
read_excel関数を使います。
1 | pd.read_excel('foo.xlsx', 'Sheet1', index_col=None, na_values=['NA'])
|
A | B | C | D | |
---|---|---|---|---|
2000-01-01 | 0.266457 | -0.399641 | -0.219582 | 1.186860 |
2000-01-02 | -1.170732 | -0.345873 | 1.653061 | -0.282953 |
2000-01-03 | -1.734933 | 0.530468 | 2.060811 | -0.515536 |
2000-01-04 | -1.555121 | 1.452620 | 0.239859 | -1.156896 |
2000-01-05 | 0.578117 | 0.511371 | 0.103552 | -2.428202 |
2000-01-06 | 0.478344 | 0.449933 | -0.741620 | -1.962409 |
2000-01-07 | 1.235339 | -0.091757 | -1.543861 | -1.084753 |
... | ... | ... | ... | ... |
2002-09-20 | -10.628548 | -9.153563 | -7.883146 | 28.313940 |
2002-09-21 | -10.390377 | -8.727491 | -6.399645 | 30.914107 |
2002-09-22 | -8.985362 | -8.485624 | -4.669462 | 31.367740 |
2002-09-23 | -9.558560 | -8.781216 | -4.499815 | 30.518439 |
2002-09-24 | -9.902058 | -9.340490 | -4.386639 | 30.105593 |
2002-09-25 | -10.216020 | -9.480682 | -3.933802 | 29.758560 |
2002-09-26 | -11.856774 | -10.671012 | -3.216025 | 29.369368 |
1000 rows × 4 columns
16. 参考リンク
16.1. 公式ドキュメント
[1] | Intro to Data Structures |
[2] | Essential Basic Functionality |
[3] | Indexing and Selecting Data "Selection By Label" |
[4] | Indexing and Selecting Data "Selection By Position" |
[5] | Working with missing data |
[6] | Essential Basic Functionality "Flexible binary operations" |
[7] | Essential Basic Functionality "Value counts (histogramming) / Mode" |
[8] | Working with Text Data |
[9] | Merge, join, and concatenate |
[10] | Merge, join, and concatenate "Database-style DataFrame joining/merging" |
[11] | Merge, join, and concatenate "Concatenating using append" |
[12] | Group By: split-apply-combine |
[13] | MultiIndex / Advanced Indexing "Hierarchical indexing (MultiIndex)" |
[14] | Reshaping and Pivot Tables "Reshaping by stacking and unstacking" |
[15] | Reshaping and Pivot Tables "Pivot tables" |
[16] | Time Series / Date functionality |
[17] | Categorical Data |
[18] | Visualization |
[19] | Writing to CSV format |
[20] | CSV & Text files |
[21] | HDF5 (PyTables) |
[22] | Excel files |
16.2. その他
- Python pandas データ選択処理をちょっと詳しく <前編> - StatsFragments
- Python pandas データ選択処理をちょっと詳しく <中編> - StatsFragments
- Python pandas データ選択処理をちょっと詳しく <後編> - StatsFragments
以下の各記事の対象Ver.は、記事中に明記されているもの以外は、記事の更新日時で判断しています。
16.2.2. pandas 0.18.1を対象とした記事
[24] | (1, 2, 3, 4, 5, 6, 7, 8) [Python] pandasの使い方まとめ - Qiita |
[25] | (1, 2, 3, 4) Pandas の DataFrame の基本的な使い方 - akiyoko blog |
16.2.3. pandas 0.17.1以前を対象とした記事
[26] | (1, 2) Pythonでpandasを使う - 計算物理屋の研究備忘録 (pandas 0.20.1から非推奨になった.ixが使われていることに注意) |
16.2.4. pandas 0.16.2以前を対象とした記事
[27] | (1, 2, 3) データ分析ライブラリPandasの使い方 - Librabuch (pandas 0.17.0から廃止になったsort()が使われていることに注意) |