読者です 読者をやめる 読者になる 読者になる

Volo di notte

お勉強の成果メモや日常のこと

Pandas Groupbyの練習 (チートシート?)

Python DataScience Pandas

Pandasを使っているとGroupbyな処理をしたくなることが増えてきます。ドキュメントを読んだりしながらよく使ったりする機能の骨格をまとめました。手っ取り早く勉強するなら、本が簡単そうです。

Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理

Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理

では、さっそくスタート。

pandasライブラリなどなどの読み込み

普段使っている感じのものをコピペ。matplotlibはinlineの方が好き。

%matplotlib inline
# %matplotlib notebook
import sqlite3
import pandas as pd
from matplotlib import pylab as plt
import numpy as np

from datetime import datetime
import dateutil

csvからpandasへのデータの読み込み

Climate Data Onlineから引っ張ってきた2016年1月の東京と京都に関する気象データをちょっと加工したものを使用。アメリカが出典なだけあって、単位がアメリカ風味。

df = pd.read_csv('./201601.csv',encoding="SHIFT-JIS")
df.head()
Station YEARMODA TEMP MAXT MINT WDSP MXSPD
0 Tokyo 20160101 45.1 53.8 37.2* 4.9 9.9
1 Tokyo 20160102 45.3 56.1 36.7 2.5 6.0
2 Tokyo 20160103 49.6 61.2 37.4 3.0 5.1
3 Tokyo 20160104 49.9 59.4 39.9 3.4 6.0
4 Tokyo 20160105 51.5 59.7 41.2 3.3 5.1
  1. Station : 観測地点。今回は東京か京都。
  2. YEARMODA : YYYYMMDDフォーマットの年月日データ
  3. TEMP : 1日の平均気温。単位 華氏[℉]
  4. MAXT : 1日の最高気温。単位 華氏[℉] *印付きには事情があるのだが、今はゴミ。
  5. MINT : 1日の最低気温。単位 華氏[℉] *印付きは事情があるのだが、今はゴミ。
  6. WDSP : 1日の平均風速。単位 1/10ノット
  7. MXSP : 1日の最大風速。単位 1/10ノット
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 60 entries, 0 to 59
Data columns (total 7 columns):
Station     60 non-null object
YEARMODA    60 non-null int64
TEMP        60 non-null float64
MAXT        60 non-null object
MINT        60 non-null object
WDSP        60 non-null float64
MXSPD       60 non-null float64
dtypes: float64(3), int64(1), object(3)
memory usage: 3.4+ KB

pandasでのdatetime型への変換; 文字列→浮動小数点変換

ちょっとした前処理をします。MAXT, MINTがたまに入っている*のせいでobject扱いに。floatに直そう。ついでにYEARMODAも変換。

# YEARMODAをdatetime型にパース
df['YEARMODA'] = df['YEARMODA'].apply(lambda x: dateutil.parser.parse(str(x)))
# *を除去してfloat型に。
df['MAXT'] = df['MAXT'].apply(lambda x: float(str.replace(x, '*', '')))
df['MINT'] = df['MINT'].apply(lambda x: float(str.replace(x, '*', '')))
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 60 entries, 0 to 59
Data columns (total 7 columns):
Station     60 non-null object
YEARMODA    60 non-null datetime64[ns]
TEMP        60 non-null float64
MAXT        60 non-null float64
MINT        60 non-null float64
WDSP        60 non-null float64
MXSPD       60 non-null float64
dtypes: datetime64[ns](1), float64(5), object(1)
memory usage: 3.4+ KB
df.head()
Station YEARMODA TEMP MAXT MINT WDSP MXSPD
0 Tokyo 2016-01-01 45.1 53.8 37.2 4.9 9.9
1 Tokyo 2016-01-02 45.3 56.1 36.7 2.5 6.0
2 Tokyo 2016-01-03 49.6 61.2 37.4 3.0 5.1
3 Tokyo 2016-01-04 49.9 59.4 39.9 3.4 6.0
4 Tokyo 2016-01-05 51.5 59.7 41.2 3.3 5.1

Pandasの行方向計算

華氏から摂氏への変換

[C] = ([F] − 32) * 5/ 9で変換

df["TEMP"] = (df["TEMP"]-32)*5/9
df["MAXT"] = (df["MAXT"]-32)*5/9
df["MINT"] = (df["MINT"]-32)*5/9

風速:0.1ノットからm/sへの変換

0.1 ノット = 0.0514444[m/s]だそうです

df["WDSP"] *= 0.051444
df["MXSPD"] *= 0.051444
df.head()
Station YEARMODA TEMP MAXT MINT WDSP MXSPD
0 Tokyo 2016-01-01 7.277778 12.111111 2.888889 0.252076 0.509296
1 Tokyo 2016-01-02 7.388889 13.388889 2.611111 0.128610 0.308664
2 Tokyo 2016-01-03 9.777778 16.222222 3.000000 0.154332 0.262364
3 Tokyo 2016-01-04 9.944444 15.222222 4.388889 0.174910 0.308664
4 Tokyo 2016-01-05 10.833333 15.388889 5.111111 0.169765 0.262364

groupbyとグループ毎での統計量

観測地点ごとにグルーピングして統計情報を出力をする練習。東京、京都それぞれの2016年1月の平均気温の平均、2016年1月の最高気温・最低気温を出してみましょう。

個別に出力する

統計量を個別に出力する場合です。あとでまとめて出す方法やります。

平均気温の平均

df.groupby("Station")["TEMP"].mean()
Station
Kyoto    5.881226
Tokyo    6.035842
Name: TEMP, dtype: float64

最高気温

df.groupby("Station")["MAXT"].max()
Station
Kyoto    16.000000
Tokyo    16.222222
Name: MAXT, dtype: float64

最低気温

df.groupby("Station")["MINT"].min()
Station
Kyoto   -4.111111
Tokyo   -2.611111
Name: MINT, dtype: float64

参考:Pandas組み込みのGroup用統計関数

上で使った基本的なもの以外にも、Essential Basic Functionality — pandas 0.19.2 documentationにある通り、いろいろな関数が組み込まれています。抜粋して翻訳。

関数 機能
count Non-Nullなデータの数
sum 合計値
mean 平均値
mad 平均絶対偏差
median メジアン(中央値)を出力
min 最小値
max 最大値
mode モード(最頻値)
abs 絶対値
prod 総乗
std 標準偏差. 自由度を引数にとれるがデフォルトは1.
var 不偏分散
sem 平均値の標準誤差(cf : 推計統計学)
skew 歪度
kurt 尖度
quantile 分位数またはクォンタイル。デフォルトでは中央値を出力する。
.quantile(.25)で25パーセンタイルを出力。
[参考]pandas.quantile — pandas
cumsum 累積和を出力(デフォルトで行方向)
cumprod 累積乗を出力 (デフォルトで行方向)
cummax 累積最大値。axis指定が必要。
cummin 累積最小値。累積最大値と似てる。

まとめて出力する

個別に統計量を出力させてもよいのですが、まとめてバッっと出したい場合は。.agg関数を使うと素敵になる。

aggregations = {
    'TEMP': {
        '1月の平均気温の平均': 'mean'
    },
    'MAXT': {
        '1月の最高気温' : 'max'
    },
    'MINT': {
        '1月の最低気温' : 'min'
    }
}
df.groupby("Station").agg(aggregations)
TEMP MAXT MINT
1月の平均気温の平均 1月の最高気温 1月の最低気温
Station
Kyoto 5.881226 16.000000 -4.111111
Tokyo 6.035842 16.222222 -2.611111

Groupbyとmatplotlib

Pandasでグループ毎に分けてプロットする方法。連続してプロットすると重ね描きになるのはmatplotlibと同様。

cmap = plt.get_cmap('rainbow')
fig, ax = plt.subplots()

#df['YEARMODA'] = df.YEARMODA.astype(np.int64)

for i, (key, group) in enumerate(df.groupby(['Station']), start=1):
    ax = group.plot(ax=ax, x='YEARMODA', y='TEMP',color=cmap(i / 4.0),label = key+"_avg")
    
for i, (key, group) in enumerate(df.groupby(['Station']), start=1):
    ax = group.plot(ax=ax, x='YEARMODA', y='MAXT',color=cmap(2*(i+1) / 4.0),label = key+"_max")
    
plt.title(u"2016/01 Temp")
fig.patch.set_facecolor('white') 
plt.show()

f:id:Chachay:20170212151243p:plain

Groupレベルの処理をDataFrameに戻す

Group別の処理結果を使って、元のデータを処理したい時のお話。

DataFrameにGroup別最大値を追加

DataFrameに、観測地別2016年1月最高気温をMAXT_Monthという列名で追加

df['MAXT_Month'] = df.loc[df.groupby('Station')['MAXT'].transform('idxmax'), 'MAXT'].values

## 別の方法
# df = df.join(df.groupby('Station')['MAXT'].max(), on='Station', rsuffix='_Month')

df.head()
Station YEARMODA TEMP MAXT MINT WDSP MXSPD MAXT_Month
0 Tokyo 2016-01-01 7.277778 12.111111 2.888889 0.252076 0.509296 16.222222
1 Tokyo 2016-01-02 7.388889 13.388889 2.611111 0.128610 0.308664 16.222222
2 Tokyo 2016-01-03 9.777778 16.222222 3.000000 0.154332 0.262364 16.222222
3 Tokyo 2016-01-04 9.944444 15.222222 4.388889 0.174910 0.308664 16.222222
4 Tokyo 2016-01-05 10.833333 15.388889 5.111111 0.169765 0.262364 16.222222

Group別に他の列の条件に応じて代入値を決める

例えば、観測地別2016年1月 最高気温日の最大風速をMXSPD_of_DAY_MAXTという列名で追加

df['MXSPD_of_DAY_MAXT'] = df.loc[df.groupby('Station')['MAXT'].transform('idxmax'), 'MXSPD'].values
df.head()
Station YEARMODA TEMP MAXT MINT WDSP MXSPD MAXT_Month MXSPD_of_DAY_MAXT
0 Tokyo 2016-01-01 7.277778 12.111111 2.888889 0.252076 0.509296 16.222222 0.262364
1 Tokyo 2016-01-02 7.388889 13.388889 2.611111 0.128610 0.308664 16.222222 0.262364
2 Tokyo 2016-01-03 9.777778 16.222222 3.000000 0.154332 0.262364 16.222222 0.262364
3 Tokyo 2016-01-04 9.944444 15.222222 4.388889 0.174910 0.308664 16.222222 0.262364
4 Tokyo 2016-01-05 10.833333 15.388889 5.111111 0.169765 0.262364 16.222222 0.262364