pandasでデータ分析する時によく使う手法覚書き（初学者用）

#はじめに
pandasでデータ分析する時によく使う手法をまとめました。随時、加筆修正していきます。



#1.DataFrameの作成
```python
#DataFrameを作成し、リストを格納
pd_sample = pd.DataFrame(リスト)

#DataFrameを作成し、辞書で複数のリストを格納
pd_sample = pd.DataFrame({"列A":リストA, "列B":リストB})

#空のDataFrameを作成し、後続処理で別のDataFrameを結合
pd_sampleA = pd.DataFrame()
pd_sampleA = pd.concat([pd_sampleA, pd_sampleB])

#列の追加
B = {a:b for a in A for b in B if x[a,b].value() == 1}
pd_sample['列B'] = pd_sample['列A'].map(B)
```



#2.データの結合(ユニオン)
```python
#pandas.concat()関数
pd_sampleAll = pd.concat([pd_sampleA, pd_sampleB], ignore_index=True)
```

**pd_sampleA**

|     | 列A　 | 列B　  | 列C　  |
|:----|-------|-------|-------|
| 0   | a     | b     | c     |

**pd_sampleB**

|     | 列C　 | 列D　 |
|:----|-------|-------|
| 0   | y     | z     |

**pd_sampleAll = pd.concat([pd_sampleA, pd_sampleB], ignore_index=True)**

|     | 列A　 | 列B　 | 列C　 | 列D　 |
|:----|-------|-------|-------|------:|
| 0   | a     | b     | c     | NaN   |
| 1   | NaN   | NaN   | y     | z     |



#3.データの結合(ジョイン)
```python
#pandas.merge()関数
pd_sampleAll = pd.merge(pd_sampleA, pd_sampleB, on="列ラベル", how="left")

#pandas.DataFrameのmerge()メソッド
pd_sampleAll = pd_sampleA.merge(pd_sampleB, on="列ラベル", how="left")

#複数の列をキーに結合
pd_sampleAll = pd.merge(pd_sampleA, pd_sampleB, on=["列A", "列B"], how="left")

#キーの列名が異なる場合の結合
pd_sampleAll = pd.merge(pd_sampleA, pd_sampleB, left_on="列A", right_on="列AAA", how="left")
```

**pd_sampleA**

|     | 列A　 | 列B　  | 列C　  |
|:----|-------|-------|-------|
| 0   | a     | b     | c     |
| 1   | aaa   | bbb   | ccc   |

**pd_sampleB**

|     | 列A　 | 列D　 |
|:----|-------|-------|
| 0   | a     | x     |
| 1   | aa    | y     |

**pd_sampleAll = pd.merge(pd_sampleA, pd_sampleB, on="列A", how="left")**

|     | 列A　 | 列B　 | 列C　 | 列D　 |
|:----|-------|-------|-------|------|
| 0   | a     | b     | c     | x    |
| 1   | aaa   | bbb   | ccc   | NaN  |



#4.データの抽出
```python
#列名指定でpandas.DataFrameを抽出
pd_sampleA = pd_sampleAll[["列A", "列B"]]

#pandas.loc()関数で行ラベルと列ラベルの位置を指定して抽出
#単一行取り出す時はSeries型、複数行取り出した時はDataFrame型が返る
#行ラベルには行名のほかにboolean型を返す条件式を指定することもできる
#複数列、行をスライスすることもできる
pd_sampleA = pd_sampleAll["列ラベル"].loc["行ラベル"]
pd_sampleA = pd_sampleAll.loc["行ラベル", "列ラベル"]
pd_sampleA = pd_sampleAll.loc[pd_sampleAll["列ラベル"]!=9999]

#pandas.iloc()関数で行番号と列番号の位置を指定して抽出
#単一行取り出す時はSeries型、複数行取り出した時はDataFrame型が返る
#複数列、行をスライスすることもできる
pd_sampleA = pd_sampleAll.iloc["行番号", "列番号"]

#pandas.isin()メソッドで引数に渡したリストの要素と一致する行を抽出
pd_sampleA = pd_sampleAll["列ラベル"].isin([ "A", "B"])
```

**pd_sampleAll**

|     | 列A　 | 列B　 | 列C　 | 列D　 |
|:----|-------|-------|-------|------|
| 0   | a     | b     | c     | d    |
| 1   | aaa   | bbb   | ccc   | ddd  |

**pd_sampleA = pd_sampleAll.loc[pd_sampleAll["列A"]=="aaa", ["列B", "列C"]]**

|     | 列B　 | 列C　 |
|:----|-------|-------|
| 1   | bbb   | ccc   |



#5.欠損値の確認
```python
#pandas.Series.isnull()メソッドで欠損値の存在する行を取得
pd_sample = pd_sample["列A"].isnull()

#isnull()メソッドにany()を用いて欠損値を含む列の有無を確認
pd_sample["列A"].isnull().any(axis=0)

#isnull()メソッドにsum()を用いて欠損値を含む列の数を確認
pd_sample["列A"].isnull().sum()

#pandas.DataFrame.dropna()メソッドで特定の列が欠損している行を削除
pd_sample = pd_sample.dropna(subset=["列A"])

#pandas.DataFrame.fillna()メソッドで欠損値を任意の値に置換
pd_sample = pd_sample.fillna({"列A": "AAA", "列B": "BBB"}))
pd_sample["age"] = pd_sample["age"].fillna(pd_sample["age"].mean())
```



#6.日付変換
```python
#pandas.to_datetime()関数で文字列(object型)をdatetime型に変換
import datetime
pd_sample["日付"] = pd.to_datetime(pd_sample["日付"])

#datetime型に対してdtアクセサを用いて年月日、時分秒、曜日などを取得
pd_sample["月"] = pd_sample["日付"].dt.month

#datetime型のstrftime()メソッドで日時を任意の書式の文字列に変換
pd_sample["年月"] = pd_sample["日付"].dt.strftime("%Y%m")

#datetime型のtimedeltaオブジェクトのtotal_seconds()メソッドを用いて２つの時間の差を取得
pd_sample["経過時間"] = (pd_sample["日付1"] - pd_sample["日付2"]).map(lambda x: x.total_seconds()/3600)
#applyを使った場合
#def calc_delta(t):
#    t1, t2 = t
#    delta = t2 - t1
#    return delta.total_seconds()/3600
#pd_sample["経過時間"] = pd_sample[["日付1"], ["日付2"]].apply(calc_delta, axis=1)

#datetime型のtimedeltaオブジェクトの days()メソッドを用いて２つの日付の日数差を取得
pd_sample["経過日数"] = (pd_sample["日付1"] - pd_sample["日付2"]).map(labda x: x.days)

#dateutilモジュールのrelativedeltaオブジェクトを用いて２つの日付の月数差を取得
#戻り値に２つの日付の差が(years=+1, months=+10, days=+8)という形で格納される
from dateutil.relativedelta import relativedelta
delta = relativedelta(pd_sample["日付1"], pd_sample["日付2"])
pd_sample["経過月数"] = delta.years*12 + delta.months

#dateutilモジュールのrelativedeltaオブジェクトを用いて任意の時間差のデータを取得
pd_sample["1ヶ月前"] = pd_sample['日付'].map(lambda x: x - relativedelta(months=1))
```



#7.集計
```python
#DataFrame型同士の演算
pd_ratio = (pd_sampleA / pd_sampleAll) * 100

#pandas.DataFrame.groupby()関数でまとめたい列と集計方法を指定して集計
#デフォルトではグループラベルがindexになるため、そうしたくない場合はas_index=Falseを指定する。
pd_count = pd_sample.groupby("まとめたい列").count()
pd_sum = pd_sample.groupby(["まとめたい列1", "まとめたい列2"], as_index=False).sum()[["合計したい列1", "合計したい列2"]]

#pandas.DataFrame.resample()メソッドで時系列データを集約
#引数にD(日)、W(週)などの頻度を指定し、sum()、count()、mean()などのメソッドを呼び出すことで集約した値を算出
pd_resampled = pd_sample.resample('D').sum()

#pandas.unique()関数で重複を除外したユニークなデータ件数を取得
pd_unique = pd.unique(pd_sample["列A"])
pd_unique = pd_sample["列A"].unique()
```



#8.その他の手法
```python
#pandas.agg()関数で特定の列の平均値、中央値、最大値、最小値を出力
pd_sample = pd_sample.agg(["mean", "median", "max", "min"])["集計したい列"]

#pandas.DataFrame.describe()関数でデータ件数、平均値、標準偏差、最小値、四分位数、中央値、最大値を出力
#デフォルトでは数値（整数型int、浮動小数点型float）の列のみが選択される
pd_sample.describe()

#DateFrame型に対してstrアクセサを用いて文字列を操作
pd_sample["列A"] = pd_sample["列A"].str.replace(" ", "")

#pandas.DataFrameのwhere()メソッドで条件に応じて値を代入する
#Trueの場合は呼び出し元のオブジェクト、Falseの場合は第二引数が適用される
pd_sample["列A"] = pd_sample["列A"].where(pd_sample["列B"]>3, 0)

#pandas.DataFrameのmask()メソッドで条件に応じて値を代入する
#Trueの場合は第二引数、Falseの場合は呼び出し元のオブジェクトが適用される
pd_sample["列A"] = pd_sample["列A"].mask(pd_sample["列B"]>3, 0)

#DataFrame型をリスト型に変換
pd_sample_columns = pd_sample.columns.tolist()

#pivotをmeltする
pd_sample_vertical = pd_sample.melt(id_vars=['列A'], value_vars=['列B', '列C', '列D'], var_name='列BCD', value_name='列BCD値')
```