オレオレ流Pandas チートシート ※随時更新※

完全な備忘録です。
ある程度まとまったら見やすい形に編集しますが、それまでは殴り書きです。
ご容赦ください。

#全般編

##import方法

```python
import pandas as pd
```

##CSVファイルの読み込み

```python
df = pd.read_csv('name.csv')

# ヘッダがないファイルを読み込む場合
# この方式で読み込まないと、1行目のデータがヘッダとして読み込まれてしまう
df = pd.read_csv('sample.csv', header=None)
```

##CSVデータヘの出力

```python
# 変数.to_csv('出力ファイル名', index=None, header=None)
# index:行番号を出力するか
# header:ヘッダを出力するか
sample.to_csv('submit1.csv', index=None, header=None)
```

##データフレームの最初の5行のみ表示

```python
df.head()
```

##出力する列数を増やす方法

```py
# 現在の最大表示列数の出力
pd.get_option("display.max_columns")
# 最大表示列数の指定（ここでは30列を指定）
pd.set_option('display.max_columns', 30)
```

##1つのカラムに出力する文字数を増やす方法

```py
#カラム内の文字数。デフォルトは50
pd.set_option('display.max_colwidth', 5000)
```

## データフレームの結合（行方向）
同じカラムを持つデータフレームを結合するには`pd.concat`を使用する

```py
hotlink = pd.concat([hotlink_akan, hotlink_towada, hotlink_nikko, hotlink_ise, hotlink_ooyama, hotlink_aso, hotlink_kirishima, hotlink_girama])
```

##データフレームのソート（members順に並び替え、10行だけ表示）

```python
df.sort_values('members', ascending=False)[:10]
```

上記のままだと、元のデータフレームはソートされない。  
元のデータフレームをソートさせたい場合は、`inplace=True`オプションを付与する必要がある。
```py
df.sort_values('members', ascending=False, inplace=True)
```

##基本統計量の確認

```python
df.describe()
# 四捨五入する場合
round(df.describe(), 2)
```

## 表示桁数の制限（対数表示から逃れる）

```py
pd.options.display.float_format = '{:.3f}'.format
```

##データフレームの型を調べる

```py
print(df.dtypes)
```

##特定カラムの平均値、中央値を表示する

```python
df['y'].mean()
df['y'].median()
```

##2つ以上のカラムを選択したい場合

```python
# [[]]2重かっこを用いる
df[['y', 'x', 'z']]
```

##データの型を確認する

```python
df.info()
```

##特定の値以上のデータをもつ行を表示

```python
df[df['y'] >= 150]
df[df['x'] == 'test']
```

##データフレームのXX行目のデータを表示する

```python
# 例えば3行目を表示したい場合
df[3:4]
```

#データの前処理に使える？編

##条件に合ったデータのみ表示・検索

```python
# dfのcolumn_nameが'test'のデータのみ表示
df[df['column_name'] == 'test'].head(10)

# 複数の条件を指定する
df[(df['column_name'] == 'test') & (df['time'] > '2016-01-01')]

# 特定の文字列を含む行を検索（下の例はname列にlの文字が含まれている行を検索）
df['name'].str.contains('l')

# 特定の文字列を含む行のユニークな列を表示
# データフレームのassetCode列に`FB`の文字列が含まれているデータの
# ユニーク一覧を表示する。assetCode以外の値は平均(mean)が表示される
df[df['assetCode'].str.contains('FB')].groupby('assetCode').mean()
```

##　空のカラム（列）を追加する

```py
df['park'] = ''
```

## データフレームを行毎にループさせながら、その行の特定カラムの値によって処理を分岐させる

```py
# 下記はデータフレームの「地点」カラムの値によって、元のデータフレームの「park」項目を再設定している
for index, item in weather.iterrows():
  if item['地点'] == '日光':
    weather.at[index, 'park'] = '日光国立公園'
  if item['地点'] == '十和田':
    weather.at[index, 'park'] = '十和田八幡平国立公園'
  if item['地点'] == '渡嘉敷':
    weather.at[index, 'park'] = '慶良間諸島国立公園'
  if item['地点'] == '熊本':
    weather.at[index, 'park'] = '阿蘇くじゅう国立公園'
  if item['地点'] == '釧路':
    weather.at[index, 'park'] = '阿寒摩周国立公園'
  if item['地点'] == '鹿児島':
    weather.at[index, 'park'] = '霧島錦江湾国立公園'
  if item['地点'] == '大田':
    weather.at[index, 'park'] = '大山隠岐国立公園'
```

##　データのカラム数に応じてデータを切り落とす

```python
# membersの値が10,000より大きいデータのみに変更
df = df[df['members'] > 10000]
```

## MultiIndexの扱い方
下記のようにカラム名が付いている場合、`df['id']`でアクセスすることはできない。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193032/b70caa77-ae34-f7f4-44a5-09a020d4479d.png)

一度、`df2 = df.reset_index()`としてindexをリセットすると、下記のようになる
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193032/b8636f08-6024-eee1-d108-d87942641bf9.png)

これで`df2['id']`でアクセスすることが可能になる。（この処理を行うと、`variable`のカラムがindexとなる）

ちなみにコードで確認することもできる。

```py
df.index.name, df.columns.name
#-> ('id', 'variable')
```

参考URL
[pandasのMultiIndexについて](https://qiita.com/ryskchy/items/59028f1a3ed1d433b1a8)

## object型の日付をdatetime型に変換する

```py
# pd.to_datetime関数を用いる
weather['年月日']  = pd.to_datetime(weather['年月日'])
```

##欠損値の取り扱い
###欠損データの確認

```python
df.isnull().sum()
```

###欠損値の割合、値のバリエーションを調べる関数

```python
def null_search(df):
    for i in df.columns:
        print("■■■  " + i )
        print("NULL数:" + str(df[i].isnull().sum() )+
            "　　　　NULL率:" + str((df[i].isnull().sum()/len(df)).round(3)) +
            "    データの種類数:" + str(df[i].value_counts().count()))

null_search(df)        
```

###NaNを探してテーブルにする関数（上記と類似）

```python
def missing_values_table(df): 
    mis_val = df.isnull().sum()
    mis_val_percent = 100 * df.isnull().sum()/len(df)
    mis_val_table = pd.concat([mis_val, mis_val_percent], axis=1)
    mis_val_table_ren_columns = mis_val_table.rename(
    columns = {0 : 'Missing Values', 1 : '% of Total Values'})
    return mis_val_table_ren_columns 

missing_values_table(df)
```


###欠損値に各カラムの平均値を設定する（数値列のみ適用される）

```python
df = df.fillna(df.mean())
```

####欠損値に一律の値を設定（元のオブジェクト自体を変更する場合）

```py
df['column'].fillna('test', inplace=True)
```

###欠損データNaNをデータセットから取り除く

```python
df = df.dropna()
```

欠損値関連で参考になるページ

- [pandasで欠損値NaNを除外（削除）・置換（穴埋め）・抽出](https://note.nkmk.me/python-pandas-nan-dropna-fillna/)

##データをマージ

```python
# suffixesは同一のカラム名が存在した場合に、後ろに文字列を追加して区別します。 (デフォルトは ‘_x’, ‘_y’)
mergeddf = df.merge(df2, left_on = 'anime_id', right_on = 'anime_id', suffixes= ['_user', ''])
```

下記のような書き方で、複数keyを対象としてマージもできる
`on=`の部分にkeyを複数指定する

```py
student_merge = pd.merge(student_data_math, student_por, on=["school","sex","age","address","famsize","Pstatus","Medu","Fedu","Mjob","Fjob","reason","nursery","internet"] ,suffixes=('_math', '_por'))
```

参考URL
[Pandas でデータフレームの結合 (マージ, JOIN) – Python でデータサイエンス](https://pythondatascience.plavox.info/pandas/pandas%E3%81%A7%E3%83%87%E3%83%BC%E3%82%BF%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%82%92%E7%B5%90%E5%90%88)

##必要なカラムだけを選択して、新しいDFにする

```python
mergeddf = mergeddf[['user_id','name','rating_user']]
```

##重複行を削除する

``` python
mergeddf = mergeddf.drop_duplicates(['user_id','name'])
```

##カラムの削除

```python
# axisは次元数を表しており、axis=0は行、axis=1は列を表す（デフォルトは0）
# inplace=Trueとすると、元のデータフレームが変更される デフォルトでは、元のデータフレームは変更されずに、新しいデーフレームが返される
df.drop(['user_id'], axis=1, inplace=True)

# 破壊的にカラムを取り除く場合は下記も可能
del df['user_id']
```

##型変換

```python
# 日付型へ変換
df['visit_date'] = pd.to_datetime(df['visit_date'])
```

##データを集約させる

```python
# pandasのagg関数で使うリストを作成
# これは、visitorsカラムを、total_visitorsというカラム名にして、中央値を計算させる
aggregation = {'visitors' : {'total_visitors' : 'median'}}
# 中央値と平均値をいっきに計算したい場合は下記のように記述
aggregation = {'visitors' : {'total_visitors' : ['median', 'mean']}}

# trainからair_store_idとdowをグルーピングしてvisitorsの中央値（median）を算出
# groupbyメソッドは、指定したカラム単位で値を集約することができる
# agg() メソッドメソッドは、辞書型のオブジェクトを渡すことでカラムに対して特定の集計をするように指示できる。
agg_data = train.groupby(['air_store_id', 'dow']).agg(aggregation).reset_index()
```

### 集約したカラム毎の統計量を知りたい
```py
# trainというデータフレームのparkというカラムで集約し、その合計値を算出
train_sum = train.groupby('park').sum()
train_sum.sort_values('visitors', ascending=False)

# 他にもmean(), min(), max()等が使用できる
```

##dataframeの特定のカラムを条件指定して表示

```python
# data_infoの祝日フラグが1（オン）のデータを表示
date_info[date_info['holiday_flg'] == 1].head(10)
```

## ビニング処理したい場合(等分割または任意の境界値を指定してビニング処理)

```py
pd.cut(s, 4, labels=['small', 'medium', 'large', 'x-large'])
```

##dataframeの中に重複している値が存在している場合、各値がそれぞれいくつあるかカウントする
曜日や名称などのカテゴリ変数を確認するときなどに使える

```python
train['week'].value_counts()
# > 水    43
# > 木    43
# > 火    41
# > 金    41
# > 月    39

# 又は下記でも可能
train.week.value_counts()
```

###上記のようなカテゴリデータをダミー変数化したいとき

```python
pd.get_dummies(train['week'])
```
下記のように変換される。

| 曜日 | - | 月 | 火 | 水 | 木 | 金 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|水   |→   |0|0|1|0|0|
|月   |→   |1|0|0|0|0|
|金   |→   |0|0|0|0|1|
|火   |→   |0|1|0|0|0|

### ラベルエンコードしたい場合

```py
mapping = {'月': 1, '火': 2, '水': 3, '木': 4, '金': 5}
train['week'] = train['week'].map(mapping)
```
下記のように変換される。

| 曜日 | - | 曜日 |
|:-:|:-:|:-:|
|水   |→   |3|
|月   |→   |1|
|金   |→   |5|
|火   |→   |2|

# list, array, nparray, dataframe同士の変換
下記サイトを参照
https://qiita.com/richi40/items/6b3af6f4b00d62dbe8e1


# 特徴量エンジニアリングのやり方
下記サイトが詳しい
http://rio-cloud.hatenablog.com/entry/2018/05/02/175319