Pandas Tips -よく使うコードリスト（文例集）-

Pythonをときどき使う自分は、コードの細かい書き方をすぐに忘れてしまい、毎回同じサイトや本を見たりすることになります。内容は何度も見て知っているので、書き方だけをちょっと思い出したい、という場面がしょっちゅうあります。そんなときに、よく使うコードの文例が1ページにまとまっているサイトがあると便利かなと思います。
そんな目的で、今回は[Pandas](https://pandas.pydata.org/)について、自分が良く使うコードの部品を以下に書いていきます。
解説については、冒頭に挙げた参考ページを見ていただければと思います。また、各項目にもリンクを貼ってあります。項目ごとのリンク集としても使えるかなと思います。

随時更新していきます。

動作確認：Python 3.7.9､Pandas 1.1.2

# よく参考にするページ
 -  [note.nkmk.me | Pandas 関連記事まとめ](https://note.nkmk.me/python-pandas-post-summary/)
 - [pyてよn日記 | Python:Pandas チートシート](https://pyteyon.hatenablog.com/entry/2020/04/28/221134)
 - [データ分析で頻出のPandas基本操作](https://qiita.com/ysdyt/items/9ccca82fc5b504e7913a)
 - [データサイエンティスト協会 | データサイエンス100本ノック（構造化データ加工編）](https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess)
 - [10 minutes to pandas](https://pandas.pydata.org/docs/user_guide/10min.html)

# 基本操作
 ```python
import numpy as np  # numpyのimport
import pandas as pd  # pandasのimport
pd.__version__  # バージョン確認
```

# データフレームの作成(1)
 - データフレームを新規作成する。


 ```python
# パターン1
cols = ['A', 'B', 'C', 'D']  # columns=list('ABCD')でもよい
a = np.random.randn(5,4)
df = pd.DataFrame(a, columns=cols)

# パターン2 : 空のデータフレームを作って、後からデータ（行）を追加（よく使う）
cols = ['A', 'B', 'C', 'D']
df = pd.DataFrame(index=[], columns=cols)
dfa = pd.DataFrame(np.random.randn(5,4), columns=cols)
df = df.append(dfa).reset_index(drop=True)

# パターン3 : リストからデータフレームを作成
# 1行4列
cols = ['A', 'B', 'C', 'D']
list = [[1, 2, 3, 4]]
df = pd.DataFrame(list, columns=cols)
# 4行1列
cols = ['A']
list = [1, 2, 3, 4]
df = pd.DataFrame(list, columns=cols)

# データフレームのリストの作成
df = pd.DataFrame(np.random.randn(10, 4))
pieces = [df[:3], df[3:7], df[7:]]

```

# データフレームの作成(2) Numpyの配列から
 - Numpyの配列からデータフレームを新規作成する。

 ```python
cols = ['x', 'y', 'z']
a = np.random.randn(10,2)
b = np.linspace(0, 1, 10)[:,np.newaxis] # newaxisを用いて行ベクトルの作成
c = np.hstack([a,b]) # 配列の水平方向への結合
df = pd.DataFrame(c, columns=cols)
```


# CSVファイルの読み込み、書き出し
 - csvファイルの読み込み
 - [pandasでcsv/tsvファイル読み込み（read_csv, read_table）](https://note.nkmk.me/python-pandas-read-csv-tsv/)

 ```python
filename = 'data.csv'
df = pd.read_csv(filename) # 何も指定しないと1行目がheaderとして認識され、列名columnsに割り当てられる。
df = pd.read_csv(filename, header=None) # header=Noneとすると連番[0,1,…]が列名columnsに割り当てられる。
df = pd.read_csv(filename, names=list('ABCD')) # 任意の値[names]を列名として設定
df = pd.read_csv(filename, header=2) # headerで指定した行からデータが読み込まれ、それより上の行は無視される。
df = pd.read_csv(filename, index_col=0) # index_col=0のようにindexとして使いたい列の列番号を0始まりで指定する。
                                        # 環境によってはWarningが出るので、下記のように引数engine='python'を指定する。
df = pd.read_csv(filename, skiprows=2, skipfooter=1, engine='python') # スキップする行数を指定（初めと終わり）
df = pd.read_csv(filename, nrows=1) # 行数を指定
df = pd.read_csv(filename, sep=',') # 区切り文字を指定(コンマ)、その他 スペースやタブ区切りの場合は、sep=' ', sep='\t'
```

- csvファイルヘの書き出し
- [pandasでcsvファイルの書き出し・追記（to_csv](https://note.nkmk.me/python-pandas-to-csv/)  
- [【python】pandas で to_csvするときのフォーマット](https://qiita.com/XPT60/items/f9102ce482e518bc9be4)



 ```python
df.to_csv('data.csv')
df.to_csv('data.csv', header=False, index=False) #ヘッダー、カラムなし
df.to_csv('data.csv', header=False, index=False, encoding='utf-8') # python3は'utf-8がデフォルト　
df.to_csv('data.csv', header=False, index=False, encoding='shift_jis') # 日本語を含むファイルをエクセルなどで使う場合
df.to_csv('data.csv', float_format='%10.3f') #フォーマットを指定
df.to_csv('data.tsv', sep='\t') # タブ区切り
```

- 固定書式ファイルの読み込み  
 固定書式ファイルは、例えば、”8F10.3″のように表現されるルールに従って記述されているデータ形式  
 (”8F10.3″は「1行につき浮動小数点(FLOAT)型が小数点以下3桁で10桁分の幅が8個連続している」という意味)
- [pandasでcsvを複数の区切り文字で区切って読み込むの巻](https://vucavucalife.com/pandas-de-csv-wo-multi-delimiter-de-read/)  
- [【プログラムTIPS】PYTHONでCSVファイルを固定書式に変換する](https://resp-kke.azurewebsites.net/2018/10/31/csv%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E5%9B%BA%E5%AE%9A%E6%9B%B8%E5%BC%8F%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B/)


 ```python
filename = 'data.txt' #8F10.3のデータ形式の場合 
colspecs = [(0,10),(11,20),(21,30),(31,40),(41,50),(51,60),(61,70),(71,80)]
df = pd.read_fwf(filename, skiprows=1, header=None, colspecs=colspecs)
```

# その他データの読み込み、書き出し
- クリップボードのデータの読み込み、書き出しは、エクセルからのデータをデータフレームにしたり、データフレームのデータをエクセルに貼りつけたりするときに便利！

 ```python
df = pd.read_clipboard() #クリップボードからのデータの読み込み
df = pd.read_clipboard(sep=',') # 区切り文字を指定する場合

df.to_clipboard() #クリップボードへのデータの書き込み
df.to_clipboard(sep=',')  #区切り文字を指定する場合
```

# データの表示・確認 
 - データの内容を表示、確認する。

 ```python
## データの表示、確認
df.describe  # データのサマリー
df.head()  # データの初めの部分
df.tail()  # データの終わりの部分
df.index  # インデックス
df.columns  # カラム
```

# データ型の指定、変換  

 - [pandasのデータ型dtype一覧とastypeによる変換（キャスト）](https://note.nkmk.me/python-pandas-dtype-astype/)  
 - 時系列データについては後述

 ```python
## データの型を表示
s.dtype  #Seriesの場合
df.dtypes #Dataflameの場合
## データの型を指定
s = pd.Series([0, 1, 2], dtype='float64') # 倍精度浮動小数点型
s = pd.Series([0, 1, 2], dtype='int64') # 符号あり64ビット整数型

## データの型を変換
# Seriesの場合
s_f = s.astype('float64') 

# Dataflemeの場合
cols = ['A', 'B', 'C', 'D'] 
a = [[11, 12, 13, 14],[21, 22, 23, 24]] 
df = pd.DataFrame(a, columns=cols, dtype='int64')

df_f = df.astype('float64') #一括変換
df_f = df.astype({'A':'float64'}) #任意の1列
df_f = df.astype({'A':'float64'}, {'C':'str'}) #任意の複数列
```


# データの選択

 - [10 minutes to pandas ：Selection](https://pandas.pydata.org/docs/user_guide/10min.html#selection)  


 ```python
## データの選択
df['A'] #カラム名による列の選択
df.A  # 同上
df[['A','C']] #複数カラムの場合

df[0:3] #インデックス番号による行の選択

# .locによる行と列の選択（ラベルを使用）
df.loc[:,['A','B']] # 複数列の選択
df.loc[0:2,['A','B']] # 複数列、複数行の選択

# .ilocによる行と列の選択（インデックス番号、カラム番号を使用）
df.iloc[2] # インデックスNoを指定して行を選択 
df.iloc[1:3,:2] # インデックスNo、カラムNoを指定して行、列を選択

df[df['A'] > 0] # 特定の条件を指定しての行、列の選択

```


# データの結合

- [Pandas_Cheat_Sheet](https://pandas.pydata.org/Pandas_Cheat_Sheet.pdf) 
- [10 minutes to pandas ：Merge](https://pandas.pydata.org/docs/user_guide/10min.html#selection) 
- [pandas.DataFrame, Seriesを連結するconcat](https://note.nkmk.me/python-pandas-concat/)
- [pandas.DataFrameに列や行を追加（assign, appendなど）](https://note.nkmk.me/python-pandas-assign-append/)


 ```python
# サンプルの作成
df1 = pd.DataFrame({'A': ['A1', 'A2', 'A3'],
                    'B': ['B1', 'B2', 'B3'],
                    'C': ['C1', 'C2', 'C3']},
                   index=['ONE', 'TWO', 'THREE'])
df2 = pd.DataFrame({'C': ['C2', 'C3', 'C4'],
                    'D': ['D2', 'D3', 'D4']},
                   index=['TWO', 'THREE', 'FOUR'])

# Concatを使う場合
pd.concat([df1, df2]) # 結合するデータフレームをリストやタプルで指定
pd.concat([df1, df2, df1]) # 3つ以上でもOK
pd.concat([df1, df2], axis=0) # 縦方向に連結（デフォルト）
pd.concat([df1, df2], axis=1) # 横方向に連結
pd.concat([df1, df2], join='outer') #外部結合（全ての列（または行）が残る）
pd.concat([df1, df2], join='inner') #外部結合（共通の列（または行）のみが残る）

# appendを使う場合
df1.append(df2) #df1にdf2を縦方向に連結
df1.append([df1, df2]) #リストやタプルで複数も可
```


# データの抽出(queryを中心に) 

- [pandas.DataFrame.query](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.query.html?highlight=query#pandas.DataFrame.query)　　
- [データサイエンティスト協会 | データサイエンス100本ノック（構造化データ加工編）](https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess) 

 ```python
# サンプルの作成
df1 = pd.DataFrame({'A': range(1, 6),
                   'BB': range(10, 0, -2),
                   'C C': range(10, 5, -1)})

df2 = pd.DataFrame({'A': ['A1', 'D2', 'H3'],
                    'B': ['AB1', 'BC2', 'CD3'],
                    'C': ['ABC1', 'BBC2', 'CBC3']},
                   index=['ONE', 'TWO', 'THREE'])

# シンプルな書き方
df1[df1.A > df1.BB]
df1[df1.BB == df1['C C']]

# queryを使う場合
df1.query('A > BB')
df1.query('BB == `C C`') #文字列にスペースを含む場合は、バッククォートで囲う
df1.query('BB != `C C`')
df1.query('A > BB & A > 9') # A>BB かつ A>9
df1.query('A > BB | A >= 5') # A>BB または A>=5
a = 5
df1.query('A > BB | A >= {}'.format(a)) # A>BB または A>=5(変数を使う場合)

df2.query('B.str.startswith("A")', engine='python') #B列が文字列Aで始まる行
df2.query('B.str.endswith("2")', engine='python') #B列が文字列2で終わる行
df2.query('C.str.contains("CBC")', engine='python') #C列が文字列CBCを含む行
df2.query('A.str.contains("^[D-J]", regex=True)', engine='python') #A列がアルファベットのD～Jのいずれかを含む行
df2.query('A.str.contains("^[B-H].*[2-9]$", regex=True)', engine='python') #A列の先頭がアルファベットのB～Hではじまり、末尾が数字の3～9で終わる行

```


# 時系列データ

- [Pandasドキュメント  Time series / date functionality](https://pandas.pydata.org/docs/user_guide/timeseries.html#)  
- [pandasで日付・時間の列を処理（文字列変換、年月日抽出など）](https://note.nkmk.me/python-pandas-datetime-timestamp/)  
- [日付のフォーマット：8.1. datetime — 基本的な日付型および時間型 — Python 3.6.5 ドキュメント](https://docs.python.org/ja/3.6/library/datetime.html#strftime-and-strptime-behavior)

 ```python
# 基本
import datetime  # 日付と時刻を扱うためのpythonの基本オブジェクト

start = datetime.datetime(2011, 1, 1)
end = datetime.datetime(2012, 1, 1)

index = pd.date_range(start, end) 
index = pd.date_range(start, end, freq='D') # D:日次
index = pd.date_range(start, end, freq='H') # H:毎時、T:毎分、S:毎秒
index = pd.date_range(start, periods=1000, freq="M") # M:月末ごと、MS:毎月初
index = pd.date_range(start, periods=1000, freq="W") # W:週次

index = pd.period_range("2018-04", "2020-12", freq='M') # 月ごと
index.days_in_month #月の日数を取得
```

- 時間によるインデックスと抽出

 ```python
dft1 = pd.DataFrame(
    np.random.randn(100000, 1),
    columns=["A"],
    index=pd.date_range("20130101", periods=100000, freq="T"),)

dft1.loc["2013"] # 2013年を抽出
dft1.loc["2013-1":"2013-2"] # 期間を指定して抽出(その1)
dft1.loc["2013-1-15":"2013-1-15 12:30:00"] # 期間を指定して抽出(その2)
```

- 型変換とフォーマット
- [pandas 文字列⇒Datetime変換｜時系列操作を簡単マスター！](https://www.yutaka-note.com/entry/pandas_datetime)

 ```python
dft2 = pd.DataFrame({'A': ['2017-11-01 12:24', '2017-11-18 23:00', '2017-11-18 23:00'],
                    'B': ['2017年11月1日 12時24分', '2017年11月18日 23時00分', '2017年12月5日 5時05分']})
print(dft2.dtypes, type(dft2['A'][0])) #いずれの列もobject型（各要素は文字列str型）

dft2['A'] = pd.to_datetime(dft2['A']) # datetime64[ns]型への変換
dft2['B'] = pd.to_datetime(dft2['B'], format='%Y年%m月%d日 %H時%M分') # フォーマットの指定
```


# 欠損値の扱い

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

 ```python
# 欠損値を削除
df.dropna(how='all') # すべての値が欠損値NaNである行を削除
df.dropna((how='all', axis=1)) # 列の場合
df2.dropna(how='any') # 欠損値が一つでも含まれる行を削除

# 欠損値を置換、穴埋め
df.fillna(0) # 欠損値NaNを共通の値で一律に置換(この場合は0で置換) もとのオブジェクトは変更されないことに注意！
df.fillna(0, inplace=True)  # もとのオブジェクトを変更
df.fillna(method='ffill') # 前（上）の値で置換
df.fillna(method='bfill') # 後ろ（下）の値で置換
 ```




以下、更新中