PythonのPandasを使っていると,例えば同じ名前の者同士を一括りにして,平均なり最大値を出したり,という処理を迫られることがあります.私自身,この間それを迫られた訳で,オライリーの本を読んで,どういう挙動を示すか色々試してみました.せっかくなので試した内容を,この記事にメモしておきたいと思います.
www.oreilly.co.jp
さて,今回のデータフレームは下のものを使います.
In [62]: df = pd.DataFrame(
...: {'Time': ['10:00:00', '10:00:01', '10:00:02', '10:00:03', '10:00:04','10:00:05', '10:00:06', '10:00:07', '10:00:08', '10:00:09'],
...: 'Sensor': ['T-A', 'T-B', 'T-C', 'T-B', 'T-C', 'T-A', 'T-C', 'T-B' ,'T-B' ,'T-C'],
...: 'Value': [25, 30, 104, 52, 41, 91, 102, 40 ,101 ,97]}
...: )
In [63]: df
Out[63]:
Sensor Time Value
0 T-A 10:00:00 25
1 T-B 10:00:01 30
2 T-C 10:00:02 104
3 T-B 10:00:03 52
4 T-C 10:00:04 41
5 T-A 10:00:05 91
6 T-C 10:00:06 102
7 T-B 10:00:07 40
8 T-B 10:00:08 101
9 T-C 10:00:09 97
実験か何かでセンサ類を使って,得られたデータを分析することを想定しています.それぞれ,
- 'Time':センサデータが得られた時間
- 'Sensor':センサの型番
- 'Value':センサから得られた値
を示しています.ちょっと問題設定としては苦しいかもしれませんが,練習のためと思ってご了承ください.
まずは基本的な使い方編
センサの型番で括るとこんな感じです.
In [63]: df
Out[63]:
Sensor Time Value
0 T-A 10:00:00 25
1 T-B 10:00:01 30
2 T-C 10:00:02 104
3 T-B 10:00:03 52
4 T-C 10:00:04 41
5 T-A 10:00:05 91
6 T-C 10:00:06 102
7 T-B 10:00:07 40
8 T-B 10:00:08 101
9 T-C 10:00:09 97
In [101]: df.groupby('Sensor').groups
Out[101]:
{'T-A': Int64Index([0, 5], dtype='int64'),
'T-B': Int64Index([1, 3, 7, 8], dtype='int64'),
'T-C': Int64Index([2, 4, 6, 9], dtype='int64')}
演算をしてみる
括った塊を演算にかけることが出来ます.例えば下の場合は'Sensor'でグルーピングして平均を求めています.
In [66]: df_mean = df.groupby('Sensor')['Value'].mean()
In [67]: df_mean
Out[67]:
Sensor
T-A 58.00
T-B 55.75
T-C 86.00
Name: Value, dtype: float64
時間ごとに集計してみよう編
In [63]: df
Out[63]:
Sensor Time Value
0 T-A 10:00:00 25
1 T-B 10:00:01 30
2 T-C 10:00:02 104
3 T-B 10:00:03 52
4 T-C 10:00:04 41
5 T-A 10:00:05 91
6 T-C 10:00:06 102
7 T-B 10:00:07 40
8 T-B 10:00:08 101
9 T-C 10:00:09 97
ここで無理やりTime列をDateTime 型に変換して列を追加します
In [93]: df2 = df.assign(time2=lambda xx: pd.to_datetime(xx.Time))
In [94]: df2
Out[94]:
Sensor Time Value time2
0 T-A 10:00:00 25 2017-02-05 10:00:00
1 T-B 10:00:01 30 2017-02-05 10:00:01
2 T-C 10:00:02 104 2017-02-05 10:00:02
3 T-B 10:00:03 52 2017-02-05 10:00:03
4 T-C 10:00:04 41 2017-02-05 10:00:04
5 T-A 10:00:05 91 2017-02-05 10:00:05
6 T-C 10:00:06 102 2017-02-05 10:00:06
7 T-B 10:00:07 40 2017-02-05 10:00:07
8 T-B 10:00:08 101 2017-02-05 10:00:08
9 T-C 10:00:09 97 2017-02-05 10:00:09
あとは無理やり
In [95]: df2.groupby(pd.Grouper(key='time2', freq='2s')).groups
Out[95]:
{Timestamp('2017-02-05 10:00:00', freq='2S'): 2,
Timestamp('2017-02-05 10:00:02', freq='2S'): 4,
Timestamp('2017-02-05 10:00:04', freq='2S'): 6,
Timestamp('2017-02-05 10:00:06', freq='2S'): 8,
Timestamp('2017-02-05 10:00:08', freq='2S'): 10}
In [96]: df2.groupby(pd.Grouper(key='time2', freq='2s')).max()
Out[96]:
Sensor Time Value
time2
2017-02-05 10:00:00 T-B 10:00:01 30
2017-02-05 10:00:02 T-C 10:00:03 104
2017-02-05 10:00:04 T-C 10:00:05 91
2017-02-05 10:00:06 T-C 10:00:07 102
2017-02-05 10:00:08 T-C 10:00:09 101