2
2

pandas[DataFrame]備忘録

Last updated at Posted at 2024-05-09

随時更新

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 0 1 2
R1 3 4 5
R2 6 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 0 1 2
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 0 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列が偶数の行を取得

C0 C1 C2
R0 0 1 2
R1 3 4 5
R2 6 7 8
.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 0 1 2
R1 3 4 5
R2 6 7 8
.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)
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2