pandas[DataFrame]備忘録

随時更新

## DataFrame作成

### データのみ指定
```.py
print(pd.DataFrame(data=[[0, 1, 2], [3, 4, 5]]))
#       0  1  2
#    0  0  1  2
#    1  3  4  5
```
### 列名を指定
```.py
df = pd.DataFrame(data=[[0, 1, 2], [3, 4, 5]], columns=["a", "b", "c"])
print(df)
#       a  b  c
#    0  0  1  2
#    1  3  4  5

# dictでも良い
pd.DataFrame({"a": [1, 2], "b": [2, 3], "c": [3, 4]})
```
### タイプはデータによって自動に設定される
```.py
print(df.dtypes)
#    a    int64
#    b    int64
#    c    int64
```
### データタイプを指定する場合
ただし、列毎にタイプを指定することはできない
```.py
df = pd.DataFrame(data=[[1, 2, 3], [2, 3, 4]], columns=["a", "b", "c"], dtype="Int32")
print(df.dtypes)
#    a    int32
#    b    int32
#    c    int32
```

### データタイプを列毎に指定する場合
```.py
df = pd.DataFrame(np.array([(1, 2, 3), (4, 5, 6)], dtype=[("a", "i1"), ("b", "i2"), ("c", "i4")]))
print(df.dtypes)
#    a     int8
#    b    int16
#    c    int32
```

## forループ
基本的にpandasのループ処理は遅い
### 元のDataFrame
```.py
df = pd.DataFrame(np.arange(150).reshape((50, 3)), columns=["a", "b", "c"])
#          a    b    c
#    0     0    1    2
#    1     3    4    5
#    :
#    48  144  145  146
#    49  147  148  149
```
### 単純for
```.py
for d in df:
    print(d)
#    a
#    b
#    c

# 列名が表示されるだけなので、列名だけ取りたいなら以下で
print(df.columns.values)
#    ['a' 'b' 'c']
```

### items (列ループ)
列でループされ、列名と列のSeriesが取得される
```.py
for label, ser in df.items():
    print(f"label : {label}")
    print(f"series : {ser}")
#    label : a
#    series : 0       0
#             1       3
#             :
#    label : b
#    series : 0       1
#             1       4
#             :
#    label : c
#    series : 0       2
#             1       5
#             :
```
### iterrows (行ループ)
行でループされ、行indexと行のSeriesが取得される。
基本的に遅いのでitertuplesを使ったほうが良い
```.py
for index, row in df.iterrows():
    print(f"index : {index}")
    print(f"row : {row}")
#    index : 0
#    row : a    0
#    b    1
#    c    2
#    Name: 0, dtype: int32
#    index : 1
#    row : a    3
#    b    4
#    c    5
#    Name: 1, dtype: int32
#             :
```
### itertuples (行ループ)
行でループされ、名前付きのタプルが取得される。
基本的にはiterrowsより高速
```.py
for row in df.itertuples():
    print(row)
#    Pandas(Index=0, a=0, b=1, c=2)
#    Pandas(Index=1, a=3, b=4, c=5)
#    Pandas(Index=2, a=6, b=7, c=8)

# 引数無しの場合はPandasという名前のタプルになる。別名をつけたい場合は
for row in df.itertuples(name='No'):
    print(row)
#    No(Index=0, a=0, b=1, c=2)
#    No(Index=1, a=3, b=4, c=5)
#    No(Index=2, a=6, b=7, c=8)
```
### 列を指定して行ループ
DataFrameの列を指定してループする
itertuplesよりも高速
```.py
for row in df["a"]:
    print(row)
#    0
#    3
#    6

# 複数列を指定するする場合はzipでまとめる
for row in zip(df["a"], df["b"], df["c"]):
    print(row)
#    (0, 1, 2)
#    (3, 4, 5)
#    (6, 7, 8)
```

### ループ速度の話
参考値
```.py
# 5000行データ
df = pd.DataFrame(np.arange(15000).reshape((5000, 3)), columns=['a', 'b', 'c'])

# zip(df["a"], df["b"], df["c"])
837 µs ± 47.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# df.itertuples()
2.27 ms ± 49.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# df.iterrows()
95.4 ms ± 2.72 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
```
## データ選択

### 元データ
```.py
df = pd.DataFrame(np.arange(9).reshape((3, 3)), columns=['C0', 'C1', 'C2'], index=['R0','R1','R2'])
print(df)
#        C0  C1  C2
#    R0   0   1   2
#    R1   3   4   5
#    R2   6   7   8
```

### loc
ラベル名で行とか列の単位で取得する場合に使用する
```.py
# [index名]指定
# この場合はSeriesで取得
print(df.loc["R0"])
#    C0    0
#    C1    1
#    C2    2
#    Name: R0, dtype: int32

# [[行ラベル]]の複数指定。
# この場合はDataFrameで取得される
print(df.loc[["R0", "R2"]])
#        C0  C1  C2
#    R0   0   1   2
#    R2   6   7   8

# [行ラベル:行ラベル]のスライス指定。
# この場合はDataFrameで取得される
print(df.loc["R0":"R2"])
#        C0  C1  C2
#    R0   0   1   2
#    R1   3   4   5
#    R2   6   7   8

# [行ラベル, 列ラベル]で指定
# loc[("R0", "C1")]でも同等だが基本使わないかと
print(df.loc["R0", "C1"])
#    1

# [[行ラベル], 列ラベル]のindex複数指定、単カラム指定。
# この場合はSeriesで取得
print(df.loc[["R0","R1"], "C0"])
#    R0    0
#    R1    3
Name: C0, dtype: int32

# [[行ラベル], [列ラベル]]のindex複数指定、単カラム指定。
# この場合はDataFrameで取得
print(df.loc[["R0","R1"], ["C0", "C1"]])
#        C0  C1
#    R0   0   1
#    R1   3   4

# [行ラベル:行ラベル, 列ラベル:列ラベル]のスライス指定。
# この場合はDataFrameで取得
print(df.loc["R0":"R1", "C0":"C1"])
#        C0  C1
#    R0   0   1
#    R1   3   4

# [[bool]]boolean指定。表示行を指定できる
#　これを使って条件による絞込などを行う
print(df.loc[[True, False, True]])
#        C0  C1  C2
#    R0   0   1   2
#    R2   6   7   8

# [[行表示bool], [列表示bool]]boolean指定。表示行、列を指定できる
print(df.loc[[True, False, True], [True, False, True]])
#        C0  C2
#    R0   0   2
#    R2   6   8
```

### iloc
位置番号で行とか列の単位で取得する場合に使用する。
番号で指定すること以外はlocとほぼ同じ。
```.py
print(df.iloc[0])
#    C0    0
#    C1    1
#    C2    2
#    Name: R0, dtype: int32

# マイナスでの取得も可能
print(df.iloc[-1])
#    C0    6
#    C1    7
#    C2    8
#    Name: R2, dtype: int32

# [2行目、1列目]を取得
print(df.iloc[1, 0])
#    3
```

### at
行ラベル、列ラベルで一つの値を取得する場合に使用する。
一つの値の変更もこれを使う
```.py
# at[行ラベル、列ラベル]
# at[("R0", "C0")]でも同等だが基本使わないかと
print(df.at["R0", "C0"])
#    0

# 値を変更
df.at["R0", "C0"] = 9
print(df)
#        C0  C1  C2
#    R0   9   1   2
#    R1   3   4   5
#    R2   6   7   8
```
### iat
位置番号で一つの値を取得する場合に使用する。
番号で指定すること以外はatとほぼ同じ。
```.py
# at[行ラベル、列ラベル]
# at[(0, 0)]でも同等だが基本使わないかと
print(df.at[0, 0])
#    0

# 値を変更
df.iat[0, 0] = 9
print(df)
#        C0  C1  C2
#    R0   9   1   2
#    R1   3   4   5
#    R2   6   7   8
```

### C0列を取得
||C0|C1|C2|
|:--:|:--:|:--:|:--:|
|R0|<font color="red">**0**</font>|1|2|
|R1|<font color="red">**3**</font>|4|5|
|R2|<font color="red">**6**</font>|7|8|

```.py
# df.C0と同等
print(df["C0"])
#    R0    0
#    R1    3
#    R2    6
#    Name: C0, dtype: int32
```
以下でも同じ。
このレベルの取得は[]のアクセスの方が高速
```.py
df.loc[:, "C0"]
df.iloc[:, 0]
```
### 1行目(index R0)を取得
||C0|C1|C2|
|:--:|:--:|:--:|:--:|
|R0|<font color="red">**0**</font>|<font color="red">**1**</font>|<font color="red">**2**</font>|
|R1|3|4|5|
|R2|6|7|8|

```.py
# DataFrameで取得されるので注意
print(df[0:1])
#        C0  C1  C2
#    R0   0   1   2
```
以下でも取得できるが、Seriesで取得される
```.py
df.loc[0]
print(df.iloc[0])
#    C0    0
#    C1    1
#    C2    2
#    Name: R0, dtype: int32
```
### C0列の1行目(index R0)を取得
||C0|C1|C2|
|:--:|:--:|:--:|:--:|
|R0|<font color="red">**0**</font>|1|2|
|R1|3|4|5|
|R2|6|7|8|
```.py
print(df.at[0, "C0"])
#    0
```
以下でも同じ。
```.py
df.iat[0, 0]
```
locでも取得できるが、一つの値を取得するならatの方が早い
```.py
df.loc[0, "C0"]
```
また、以下の方法でも取得はできるがdataframe→series.locしているのでat,iatを普通は使う
```.py
df["C0"][0]
df["C0"][0:1]  # ただし取得できるのはSeries
df["C0"].loc[0]
df["C0"].iloc[0]
```
### ある列の値が条件に一致する行を取得
C0列が偶数の行を取得
||<font color="yellow">**C0**</font>|C1|C2|
|:--:|:--:|:--:|:--:|
|R0|<font color="red">**0**</font>|<font color="red">**1**</font>|<font color="red">**2**</font>|
|R1|3|4|5|
|R2|<font color="red">**6**</font>|<font color="red">**7**</font>|<font color="red">**8**</font>|
```.py
print(df[df["C0"] % 2 == 0])
#        C0  C1  C2
#    R0   0   1   2
#    R2   6   7   8
```
以下でも同様
```.py
df.query("C0 % 2 == 0")
df.loc[df['C0'] % 2 == 0]
df[df.apply(lambda row: row['C0'] % 2 == 0, axis=1)]
```

### ある行の値が条件に一致する列を取得
R2行が偶数の列を取得
||C0|C1|C2|
|:--:|:--:|:--:|:--:|
|R0|<font color="red">**0**</font>|1|<font color="red">**2**</font>|
|R1|<font color="red">**3**</font>|4|<font color="red">**5**</font>|
|<font color="yellow">**R2**</font>|<font color="red">**6**</font>|7|<font color="red">**8**</font>|
```.py
print(df.loc[:, df.loc['R2'] % 2 == 0])
#        C0  C2
#    R0   0   2
#    R1   3   5
#    R2   6   8
```

### 速度の話
※あくまで参考値

単一の値を取得する場合
atが最速
```.py
# 元データ
df = pd.DataFrame(np.arange(15000).reshape((5000, 3)), columns=['a', 'b', 'c'])

# df.at[2500, "b"]
5.11 µs ± 459 ns per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
# df["b"][2500]
6.47 µs ± 883 ns per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
# df.loc[2500, "b"]
10.3 µs ± 2.66 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
# df.iat[2500, 1]
19 µs ± 4.63 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
# df.iloc[2500, 1]
28.5 µs ± 8.42 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
```

列(or行)を取得する場合
[]が最速
```.py
# 元データ
df = pd.DataFrame(np.arange(15000).reshape((5000, 3)), columns=['a', 'b', 'c'], index=[str(i) for i in range(5000)])

# df["b"]
4.51 µs ± 1.21 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
# df.loc[:, "b"]
23.8 µs ± 5.62 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
# df.iloc[:, 1]
41.5 µs ± 9.62 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
```

条件に一致する行を取得する場合
[]とlocはほぼ同等。queryは遅い
```.py
# 元データ
df = pd.DataFrame(np.arange(9).reshape((3, 3)), columns=['C0', 'C1', 'C2'], index=['R0','R1','R2'])

# df.loc[df['C0'] % 2 == 0]
279 µs ± 45.2 µs per loop (mean ± std. dev. of 7 runs, 500 loops each)
# df[df["C0"] % 2 == 0]
249 µs ± 62.6 µs per loop (mean ± std. dev. of 7 runs, 500 loops each)
# df[df.apply(lambda row: row['C0'] % 2 == 0, axis=1)]
355 µs ± 51.5 µs per loop (mean ± std. dev. of 7 runs, 500 loops each)
# df.query("C0 % 2 == 0")
1.74 ms ± 158 µs per loop (mean ± std. dev. of 7 runs, 500 loops each)
```