Blow Up by Black Swan

Python-pandasモジュールの基本的な使い方2: 10 minutes to pandas

1. はじめに

今回は以前の記事の続きになります。

各項目の通し番号も、前回の記事の続きとなるようになっています。

2. 10 minutes to pandas 続き

(5). マージ

ここで扱うのは、データに他のデータを連結したり、付加したりするメソッドです。

(5)-1. 連結

・concat()メソッド

df = pd.DataFrame(np.random.randn(10, 4))  #DataFrameオブジェクトの生成
pieces = [df[:3], df[3:7], df[7:]]   #バリューの分割
pd.concat(pieces)  #valueの結合

ここでは、単純にデータの分割->結合を行なっています。

戻り値

 0123
00.8907560.901530-0.7655551.050202
1-0.2711210.5939501.8244530.614195
20.9528801.2629620.6190880.786609
3-1.242715-0.259757-0.4413380.073672
4-1.943991-0.1568030.008432-2.172710
50.9415961.562745-0.2368990.885822
6-0.881871-1.6917230.7201650.041064
7-2.4682250.3910670.829695-0.100468
80.550700-1.3140551.3702460.488189
9-0.1248050.1901500.345547-0.401358

(5)-2. 結合

・merge()メソッド

left = pd.DataFrame({'key': ['foo', 'foo'], 'lval': [1, 2]})
right = pd.DataFrame({'key': ['foo', 'foo'], 'rval': [4, 5]})
pd.merge(left, right, on='key')  #keyを基準にDataFrameオブジェクトを結合させる

戻り値

 keylvalrval
0foo14
1foo15
2foo24
3foo25
left = pd.DataFrame({'key': ['foo', 'bar'], 'lval': [1, 2]})
right = pd.DataFrame({'key': ['foo', 'bar'], 'rval': [4, 5]})
pd.merge(left, right, on='key')  #もう1つの例

ここでは、fooとbarが一致しているので、カラムが追加される形になっています。

戻り値

 keylvalrval
0foo14
1bar25

(5)-3. 付加

・append()メソッド

#rowにDataFrameを付加
df = pd.DataFrame(np.random.randn(8, 4), columns=['A','B','C','D'])
s = df.iloc[3]
df.append(s, ignore_index=True)  #df.iloc[3]がインデックス8に付加されている

ここでは、新たにインデックスが追加されています。

戻り値

 ABCD
02.7151590.782455-0.594675-0.570256
1-0.329114-0.1865221.022586-2.380807
20.954745-2.141672-0.022732-1.165014
30.4435550.3009221.6755710.367578
40.6764510.4106470.405250-2.991596
5-0.8874300.1353060.2600990.667514
6-0.538035-0.761003-0.413540-0.988319
7-0.455442-0.5643291.090382-0.372395
80.4435550.3009221.6755710.367578

ここで登場したメソッド等は以下になります。

  • concat()…データを結合させるメソッド
  • merge()…DataFrameオブジェクトを結合させる
    • * 引数: left,right=DataFrameオブジェクト、on=結合の基準をインデックスかカラムかを指定
  • DataFrame.append()…DataFrameにrowを付加するメソッド。
    • * 引数: ignore_index=付加するrowのラベルを使用するかどうか(Trueなら使用しない)

(6). グルーピング

groupbyメソッドでグループ単位で分割や適用、結合などができます。

.groupby()メソッド

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.groupby('A').sum()  #Aグループを同一バリューごとにカテゴライズし、各カラムの値を合計する

戻り値

 CD
A  
bar-1.934583-0.343288
foo0.762228-1.428246
df.groupby(['A','B']).sum()  #グループ化をA->Bで行う

戻り値

  CD
AB  
barone-0.760050-0.479678
three-1.515467-0.274024
two0.3409340.410415
fooone1.455895-0.354460
three0.1573380.450135
two-0.851006-1.523920

ここで登場したメソッド等は以下になります。

  • DataFrame.groupby() …グループごとに沿った対応をするメソッド -> Gruoupby型
  • GroupBy.sum()…グループに沿って合計を出すメソッド

(7). 再整形

ここでは、データの整形を行うメソッドを扱っています。

(7)-1. スタック

インデックスを複数重ね合わせるようなことができます。 

tuples = list(zip(*[['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
                    ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]))  #zip(*引数)で引数を展開する -> listでタプルをリストに変換
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])  #タプルのリストをインデックスに転換する
df = pd.DataFrame(np.random.randn(8, 2), index=index, columns=['A', 'B'])
df2 = df[:4]
df2

戻り値

  AB
firstsecond  
barone0.656057-0.108284
two-0.659357-0.505724
bazone0.3790700.972001
two-0.110854-0.328280

上記のデータ構造をさらにマルチインデックスのようにします。
・stack()メソッド

stacked = df2.stack()  #DataFrame、Seriesのカラムをインデックスに入れ、マルチインデックスのような形にする
stacked

戻り値

first  second   
bar    one     A    0.427586
               B   -1.005260
       two     A    0.095713
               B    2.812249
baz    one     A   -0.244172
               B   -1.650703
       two     A   -0.789093
               B   -0.349003
dtype: float64

・unstack()メソッド

stacked.unstack()  #スタックされたDataFrame,Seriesをカラムのある状態に戻す

戻り値

  AB
firstsecond  
barone0.656057-0.108284
two-0.659357-0.505724
bazone0.3790700.972001
two-0.110854-0.328280

(7)-2. ピボットテーブル

・pivot_table()メソッド

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)})
pd.pivot_table(df, values='D', index=['A', 'B'], columns=['C'])
#スプレッドシートスタイルのピボットテーブル(データの要約)を返す。(引数の意味:DataFrameであるdfのバリューDのみが対象、A・Bがインデックス、Cがカラム)

戻り値

 Cbarfoo
AB  
oneA0.1642880.511736
B1.1132881.218575
C0.1409171.920049
threeA0.384494NaN
BNaN-0.954451
C-0.900987NaN
twoANaN-1.876843
B0.659083NaN
CNaN-0.148574

ここで使用したメソッド等は以下になります。

  • MultiIndex.from_tuples()…タプルのリストをマルチインデックスに変換する
  • DataFrame.stacked()…カラムをインデックス相当に置き換え、マルチインデックスのようにするメソッド
  • stucked DataFrame.unstacked()…スタックされたDataFrameをカラムのある状態にするメソッド
  • pivot_table()…スプレッドシートスタイルのピボットテーブル(データの要約)を返す

(8). Time Series

Pandasでは、時間についてもこのモジュールで扱えるようになっています。

・resample()メソッド

rng = pd.date_range('1/1/2012', periods=100, freq='S')
ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)
ts.resample('5Min').sum() #resample()…引数に合致する時間インデックスに会う情報を収集

戻り値

2012-01-01    25017
Freq: 5T, dtype: int64

・tz_localize()メソッド

rng = pd.date_range('3/6/2012 00:00', periods=5, freq='D')
ts = pd.Series(np.random.randn(len(rng)), rng)
ts_utc = ts.tz_localize('UTC')  #タイムゾーンを持ったawareな時間オブジェクトに変更
ts_utc

戻り値

2012-03-06 00:00:00+00:00   -0.311405
2012-03-07 00:00:00+00:00   -0.399318
2012-03-08 00:00:00+00:00   -1.052087
2012-03-09 00:00:00+00:00    1.913156
2012-03-10 00:00:00+00:00   -0.516693
Freq: D, dtype: float64

・uz_convert()メソッド

ts_utc.tz_convert('US/Eastern') #引数の地域のタイムゾーンに変更

戻り値

2012-03-05 19:00:00-05:00   -0.311405
2012-03-06 19:00:00-05:00   -0.399318
2012-03-07 19:00:00-05:00   -1.052087
2012-03-08 19:00:00-05:00    1.913156
2012-03-09 19:00:00-05:00   -0.516693
Freq: D, dtype: float64

・to_period()メソッド、to_timestamp()メソッド

#タイムインデックスの推移:月末基準(rng)->付きのみの表示(ps)->月初基準
rng = pd.date_range('1/1/2012', periods=5, freq='M')
ts = pd.Series(np.random.randn(len(rng)), index=rng)
ps = ts.to_period()  #Datatimeインデックスからperiodタイムインデックスに変更
ps.to_timestamp()   #月初日基準のdatetimeインデックスに変更

戻り値

2012-01-01    0.628367
2012-02-01   -0.418007
2012-03-01    0.302071
2012-04-01   -0.099849
2012-05-01    0.575034
Freq: MS, dtype: float64

・asfreq()メソッド

#タイムインデックスの推移:クオーター(prng)->クオーターの最初の日の9時
prng = pd.period_range('1990Q1', '2000Q4', freq='Q-NOV')
ts = pd.Series(np.random.randn(len(prng)), prng)
ts.index = (prng.asfreq('M', 'e') + 1).asfreq('H', 's') + 9  #PeriodIndexを特定の頻度期間に変更
ts.head()

戻り値

1990-03-01 09:00    0.705433
1990-06-01 09:00   -0.910949
1990-09-01 09:00   -0.280971
1990-12-01 09:00    1.644449
1991-03-01 09:00    2.460565
Freq: H, dtype: float64

ここで利用したメソッド等は以下になります。

  • Series.resample()…引数に合致する時間インデックスでデータを再取得 -> Seriesオブジェクト
  • Series.tz_localize(timezone)…引数のタイムゾーン情報を持つ時間オブジェクトに変更
  • Seriestime.tz_convert(timezone)…引数のタイムゾーンの時間に変更
  • Seriestime.to_period()…Datatimeインデックスをperiodタイムインデックスに変更
  • Seriestime.to_timestamp()…月初日基準のdatetimeインデックスに変更
  • period_range()…期間表示のタイムインデックスを返すメソッド -> PeriodIndex型
  • PeriodIndex.asfreq()…PeriodIndexオブジェクトを特定のタイムインデックスに変換

(9). カテゴリー化

ここでは、カテゴリー化を行うメソッド等を行います。

・astype()メソッド

df = pd.DataFrame({"id":[1,2,3,4,5,6], "raw_grade":['a', 'b', 'b', 'a', 'a', 'e']})
df["grade"] = df["raw_grade"].astype("category")  #"raw_grade"のデータを"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]

・cat_categories属性

df["grade"].cat.categories = ["very good", "good", "very bad"]  #新しいカテゴリーを割り当て[a,b,c]に相当
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]

・cat_set_categories()メソッド

df["grade"] = df["grade"].cat.set_categories(["very bad", "bad", "medium", "good", "very good"])  #新しいカテゴリーの割り当て[a,b,c]に相当
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]

・sort_values()メソッド

df.sort_values(by="grade")  #gradeでのソート

戻り値

 idraw_gradegrade
56every bad
12bgood
23bgood
01avery good
34avery good
45avery good
df.groupby("grade").size()  #gradeカテゴリーをサイズを出す

戻り値

grade
very bad     1
bad          0
medium       0
good         2
very good    3
dtype: int64

ここで使用したメソッド等は以下になります。

  • Categorical()…カテゴリー変数を表すメソッド。 -> Categorical型
  • DataFrame.astype()…pandasオブジェクトを特定のデータ型に変換
  • Series.cat.categories…新しいカテゴリーの割り当て
  • Series.cat.set_categories()…新しいカテゴリーの割り当て
  • Series.sort_values(category)…指定したカテゴリーでのソート
  • GroupBy.size()…特定グループのサイズを集計

(10). プロット

ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))
ts = ts.cumsum()
ts.plot()  #matplotlibを使ってグラフをプロット

戻り値

チャートイメージ図1

・cumsum()メソッド

df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index, columns=['A', 'B', 'C', 'D'])
df = df.cumsum()
plt.figure(); df.plot(); plt.legend(loc='best')  #セミコロンは1行に複数の文を書く場合の記法(非推奨)
#plt.figure()…Figureオブジェクトの生成
#plt.legend()…図の中で利用する凡例(左下のもの)を表示するもの

戻り値

チャートイメージ図2

ここで使用したメソッドは以下になります。

  • Series.plot()…matplotlibを用いてグラフにプロット
  • Artistクラス…図のキャンバスをレンダリングするための抽象的な基底クラス
  • Figureインスタンス…コールバックをサポートする
  • plt.figure()…figureモジュール。プロットするすべての要素を含む、Artistクラスやfigureインスタンスを提供する
  • plt.legend()…Legendモジュール。判例を表示させるためのもの。
    • 引数: loc=凡例の位置の指定
  • cumsum()…累積和を表すメソッド

(11). 他ファイルからのデータの取得

ここでは、他のファイル形式からデータを取得するメソッド等を扱います。

(11)-1. CSV

・to_csv()メソッド

df.to_csv('foo.csv')  #DataFrameをcsvに書き込み
pd.read_csv('foo.csv')  #CSVファイルをDataFrameで読み込む

戻り値

 Unnamed: 0ABCD
02000-01-01-0.8856290.8896560.6330890.056821
12000-01-02-2.9822190.4031941.2091241.959333
22000-01-03-3.1049372.1833572.9959850.641896
32000-01-04-3.4882872.8442561.020145-0.520878
42000-01-05-3.0994562.7112962.700519-1.665338
52000-01-06-1.8958602.2382602.637793-1.817670
62000-01-07-3.7121674.1380612.972879-2.315594
72000-01-08-1.9952694.1600254.245503-3.365914
82000-01-09-1.7646733.6895174.425295-3.296960
92000-01-10-2.5377733.2894953.971328-3.323374
102000-01-11-3.8041901.4545334.160079-2.408422
112000-01-12-3.1739570.8320846.127438-2.184997
122000-01-13-2.5700911.2728216.690779-0.801479
132000-01-14-2.9767941.1282425.986204-1.114424
142000-01-15-2.965553-1.1522577.227440-0.426281
152000-01-16-5.7819280.4000057.599222-1.256213
162000-01-17-6.3076841.8550037.607097-3.244378
172000-01-18-6.9590261.5979807.045685-2.287091
182000-01-19-6.3351891.4692776.135651-1.515488
192000-01-20-7.0085082.5514766.298826-0.652640
202000-01-21-7.5662811.1610195.501244-2.101572
212000-01-22-7.4887031.0066024.202419-2.114033
222000-01-23-7.5962980.3293084.716298-0.780222
232000-01-24-6.218714-0.1004615.1971342.144381
242000-01-25-6.3008950.5501335.4372010.364817
252000-01-26-5.2254940.9968875.3570272.128822
262000-01-27-5.632822-1.3215996.1615072.890215
272000-01-28-4.7828461.2641247.6715741.493188
282000-01-29-3.6443090.6123448.5559501.944154
292000-01-30-2.689048-0.33320310.2253482.428360
9702002-08-2813.87834435.52296133.97202213.754965
9712002-08-2915.37398435.45952032.70693712.694938
9722002-08-3016.29943834.10141033.31329412.354133
9732002-08-3116.32187733.25953233.06604613.003854
9742002-09-0117.72588732.64952432.87674512.741271
9752002-09-0215.96028034.01445933.49497111.525645
9762002-09-0317.62067531.68627232.93452011.444935
9772002-09-0419.28063432.95210032.10833012.894522
9782002-09-0519.32239633.43738632.39169413.351699
9792002-09-0618.85950233.73570231.63426415.322096
9802002-09-0718.09018433.37753430.12389415.055033
9812002-09-0819.49958434.68369728.93391215.674115
9822002-09-0920.02310933.22523228.03633014.623939
9832002-09-1022.09649133.46021828.29670715.325953
9842002-09-1121.17539531.86760827.87438214.080145
9852002-09-1222.74913231.55479128.80064912.878497
9862002-09-1320.67985529.10620328.78183511.242140
9872002-09-1419.94969330.34314628.95072711.268712
9882002-09-1519.82770330.30774129.63405311.303194
9892002-09-1618.84092930.48829329.96399410.921785
9902002-09-1719.09661931.97951129.26828111.851570
9912002-09-1818.91894133.58099929.98973511.241848
9922002-09-1917.52504033.09192528.30303511.107315
9932002-09-2016.83251732.69542528.26579410.618252
9942002-09-2115.99303532.88288629.0839189.858696
9952002-09-2215.49944533.89077228.10922910.657104
9962002-09-2316.67128135.68670826.9591089.960204
9972002-09-2416.52558336.75839227.8749708.786993
9982002-09-2517.49268536.95301927.2483889.385779
9992002-09-2617.58924437.61010728.8346089.139163

(11)-2. HDF5

HDF5は、Hierarchical Data Formatの略で、階層化されたデータ群を取り扱うフォーマットです。

・to_hdf()メソッド

#扱い方がよくわからないため実行せず
df.to_hdf('foo.h5','df')  #HDF5ファイルへの書き込み
pd.read_hdf('foo.h5','df')  #HDF%ファイルの読み込み

(11)-3. Excel

・to_excel()メソッド

df.to_excel('foo.xlsx', sheet_name='Sheet1')  #Excelファイルへの書き込み
pd.read_excel('foo.xlsx', 'Sheet1', index_col=None, na_values=['NA'])  #Excelファイルの読み込み

ここで使用したメソッドは以下になります。

  • DataFrame.to_csv()…DataFrameをCSVに書き込み
  • read_csv()…csvをDataFrameとして読み込み
  • DataFrame.to_hdf()…HDF5ファイルへの書き込み
  • read_hdf5()…HDF5ファイルの読み込み
  • DataFrame.to_excel()…Excelファイルへの書き込み
  • read_excel()…Excelファイルの読み込み

4. まとめ

以上が10 minutes to pandasの概要となります。

データを扱うことに特化しており、色々な使い方ができそうですので、僕も色々と試していきたいと思います。また、githubに私が学習したjupyter notebookのファイルをあげていますので、こちらも参考にしていただければと思います。