pandas
import pandas as pd
データ型
サンプルデータ
df = pd.DataFrame([
{"column1": 1, "column2": 2},
{"column1": 3, "column2": 4},
])
型を確認する
df.dtypes
column1 int64
column2 int64
dtype: object
結果はSeriesとなる。
型を変換する(一括)
_df = df.astype("str")
_df.dtypes
column1 object
column2 object
dtype: object
型を変換する(個別)
_df = df.astype({"column1": str, "column2": float})
_df.dtypes
column1 object
column2 float64
dtype: object
なお、文字列で指定しても解釈してくれる
_df = df.astype({"column1": "str", "column2": "float"})
_df.dtypes
NumPyの型も解釈可能。
import numpy as np
_df = df.astype({"column1": np.int32, "column2": np.float32})
_df.dtypespython
置換
サンプルデータ
df = pd.DataFrame([
{"column1": 1, "column2": 2},
{"column1": 3, "column2": 4},
])
辞書型で置換可能。
df.replace({1: "A", 2: "B", 3: "C", 4: "D"})
column1 column2
0 A B
1 C D
Seriesに対しても可能。
df["column1"].replace({1: "A", 2: "B", 3: "C", 4: "D"})
カラム名を置き換える場合は、キーワード引数でcolumnsを使用する。
df.rename(columns={"column1": "aaa"})
aaa column2
0 A B
1 C D
抽出(query)
user_idが重複しているレコードを抽出する例。
","で結合して、queryのinで抽出する。
user_id_str = ",".join(df[df.duplicated(['user_id'], keep='last')]['user_id'].astype(str))
df.query(f'user_id in ({user_id_str})')
カラムの並び替え
並び変えたカラムを[]に入れるだけで良い。
columns = df.columns.tolist()
columns = columns[-1:] + columns[:-1] # reorder example
df = df[columns] # do reorder!!
group集計して統計量を計算する。
既に準備されている統計計算をする場合
# user_idで集計して、年齢の統計量を計算する例
age_stats_df = rowdata_df.groupby("user_id")["age"].agg(["mean"])
# 上記では、goupbyしたカラムがindexになってしまうので、嫌な場合はreset_index()する。
age_stats_df = rowdata_df.groupby("user_id")["age"].agg(["mean"]).reset_index()
自作でpersentileなどを計算したい場合
# 自作関数を作る
def percentile(n):
def percentile_(x):
return np.percentile(x, n)
percentile_.__name__ = 'percentile_%s' % n
return percentile_
age_stats_df = rowdata_df.groupby("user_id")["age"].agg([percentile(80)]).reset_index()
時系列データを集計する場合
時刻情報がある場合、その列をindexにすることで、resampleが使えて集計できる。
購入量の時系列データのイメージで以下は'M'で月ごとの結果を集計する例。
timedomain_df.set_index("recorded_at", drop=True).sort_index().loc[:,["purchase_count"]].resample('M').agg(['sum', 'mean', "max"])
行を挿入する。
seriesをappendする。
import pandas as pd
df = pd.DataFrame([], columns=['A', 'B', 'C'])
row_data = pd.Series(['0', '1', '2'], index=df.columns)
df = df.append(row_data, ignore_index=True)
df = df.append(row_data, ignore_index=True)
dictをappendする。
df = df.append({'A': 0, 'B': 1, 'C': 2}, ignore_index=True))
df = df.append({'A': 0, 'B': 1, 'C': 2}, ignore_index=True))
列毎の欠損数を求める。
df.isnull().sum()
applyの使用法まとめ
以下ノートブック参照
query記法を使った条件抽出
カラム名に空白のある場合はバッククォートを使う。
df_receipt.query('`sales ymd` == 20181103')
placeholderは、f-stringでもかけるが、@の方が汎用性が高い。
user_id = "1000"
df.query('user_id == @user_id')
時刻系のデータをquery記法で処理
timedelta_val = timedelta(days=1)
df.query('yyyymmdd_diff > @timedelta_val')
date_val = datetime(2022,6,15)
df.query('yyyymmdd > @date_val')
たとえばtimedeltaを数値として扱いたい場合などは、datetime.timedelta
と併せて使う。
from datetime import timedelta
df['yyyymmdd_diff'] / timedelta(days=1)
read_csvで型指定
dictで各列の型を指定できる。
read_dtype = {
'yyyymmdd': 'str'
, 'column1': 'int'
, 'column2': 'float'
}
df = pd.read_csv("sample.csv", dtype=read_dtype)
日付等は以下のように後変換する。
df['yyyymmdd'] = pd.to_datetime(df['yyyymmdd'])
抽出して新しい列を作る
df = pd.DataFrame([
['aaa','aaa.pptx'],
['bbb','bbb.pptx'],
['ccc','ccc.pptx'],
], columns=['name', 'file'])
df['file'].str.extract("(.*)\.pptx")
rank: 順位を付ける
# 値が高い順(降順)、同値は小さい順位(上位)に合わせる
df['column_name'].rank(ascending=False, method='min')
unique: 出現する種類を把握する
df['column_name'].unique()
value_counts: 内訳を知る
df.value_counts('column_name')
その他のオプション
normalize=True
で比率を計算できる。bins=30
で連続値も集計できる。dropna=True
でNaNを無視できる。
sort_values: 並べ替え
# 値が高い順(降順)
df.sort_values('column_name', ascending=False)
isnull(): 欠損値かどうかを調べる
df.isnull()
df['column_name'].isnull()
dropna(): 欠損値を削除する
通常は一つでも欠損がある場合は削除される。
df.dropna()
どこかの列に基づきたい場合は、subsetで指定する。
df.dropna(subset=['column1'])
欠損値を列毎に修正する
df.loc[rank_df.query('column1 != column1').index,'column1'] = 0
locとilocの違い
locはindex(いわゆるDataFrameのIndex), column名でアクセスする。
ilocは本当のindex番号で縦横ともにアクセスする。
なのでilocを使えば、reset_index(drop=True)しなくてもアクセスしたいものにアクセスできるかもしれない
merge: joinしたいとき
だいたいこんな感じの書き方におさまる。
df\
.merge(df2[['column1', 'column2']], how='inner', on='column1')\
.merge(df3[['column1', 'column3']], how='left', on='column1')\
複数をキーにjoinしたい場合は、
on=['column1', 'column2']
とすればOK。join後に重複するカラム名は、
suffixes=['_left', '_right']
と指定すれば末尾に目印をつけられる。
groupby + agg: 集約したいとき
だいたいこんな感じの書き方におさまる。
def my_func(x):
return np.std(x)
stats_df = df.groupby('column1').agg(
new_column1 = ('org_column2', 'mean'),
new_column2 = ('org_column2', 'std'),
new_column3 = ('org_column3', my_func),
).reset_index()
grouby + transform: 集約したものを各行に割り当てる
集約となるmeanやsumは、transformにより行を元のDFに拡張することができる。
df['column2_mean'] = df.groupby(['column1'])['column2'].transform("mean")
groupby + shift, rank: 集約でない場合のgroupby + 各行割り当て
transformとかも選択肢にでてくるけど、使わなくても行ける。
集約ではなく、shiftやrankなどの場合はこの方法が使える。
df.groupby('column1')['column2'].shift(-1)
idxmin: 最小値の時のPandas Indexを得る
df['column1'].idxmin()
drop_duplicates: 重複を削除する
残すものをコントロールするためには、事前にsort_valuesしておく感じの使い方となる。
df.drop_duplicates(subset=['column1', 'column2'], keep='first') # 最初を残す
df.drop_duplicates(subset=['column1', 'column2'], keep='last') # 最後を残す
df.drop_duplicates(subset=['column1', 'column2'], keep=False) # 残さない
duplicated: 重複の判定
ほぼdrop_duplicatedと同じ。
df.duplicated(['column1','column2'], keep='last')
抽出の場合はこうする
df[df.duplicated(['column1','column2'], keep='last')]
より高度な最適化
https://www.aidancooper.co.uk/pandas-anti-patterns/
再代入をせず、chain or pipeを使う
forではなくapplyを使う
applyをさらに最適化するには、np.select, np.whereを使う
data typeを最適にする(カテゴリ型をstrにしない)
Last updated