note.nkmk.me

pandas.DataFrameに列や行を追加(assign, appendなど)

Posted: 2018-04-26 / Modified: 2020-05-21 / Tags: Python, pandas

pandas.DataFrameに新たな列または行を追加する方法を説明する。

新規の列名・行名を指定して追加する、pandas.DataFrameassign(), insert(), append()メソッドで追加する、といった方法がある。

ここでは以下の内容について説明する。

  • pandas.DataFrameに列を追加
    • 新規列名を指定して追加
    • assign()メソッドで追加・代入
    • insert()メソッドで任意の位置に追加
    • concat()関数でSeries, DataFrameを横に連結
  • pandas.DataFrameに行を追加
    • 新規行名を指定して追加
    • append()メソッドで追加
    • concat()関数でSeries, DataFrameを縦に連結
    • 転置してからassign(), insert()メソッドを使用

pandas.DataFrame, pandas.Seriesを連結するpandas.concat()関数についても簡単に触れるが、詳細は以下の記事を参照。

例として以下のオブジェクトを生成して使う。

import pandas as pd

df = pd.DataFrame({'A': ['A1', 'A2', 'A3'],
                   'B': ['B1', 'B2', 'B3'],
                   'C': ['C1', 'C2', 'C3']},
                  index=['ONE', 'TWO', 'THREE'])
print(df)
#         A   B   C
# ONE    A1  B1  C1
# TWO    A2  B2  C2
# THREE  A3  B3  C3
スポンサーリンク

pandas.DataFrameに列を追加

新規列名を指定して追加

[列名]で列を選択して値を代入できる。

df['A'] = 0
print(df)
#        A   B   C
# ONE    0  B1  C1
# TWO    0  B2  C2
# THREE  0  B3  C3

ここにまだ存在しない列名を指定することで、その列を追加して値を代入することができる。

スカラーを追加

スカラー値の場合、すべての要素がその値となる。

df['D'] = 0
print(df)
#        A   B   C  D
# ONE    0  B1  C1  0
# TWO    0  B2  C2  0
# THREE  0  B3  C3  0

array-likeオブジェクトを追加

リストやNumPy配列ndarrayなどのいわゆるarray-likeオブジェクトの場合、各要素がそのまま代入される。

df['E'] = [0, 1, 2]
print(df)
#        A   B   C  D  E
# ONE    0  B1  C1  0  0
# TWO    0  B2  C2  0  1
# THREE  0  B3  C3  0  2

追加するリストなどの要素数と行数が一致していないとエラー(ValueError)になる。

# df['F'] = [0, 1, 2, 3]
# ValueError: Length of values does not match length of index

pandas.Seriesを追加

pandas.SeriesでもOK。

pandas.DataFrameの各列を参照するとpandas.Seriesとして扱われるので、それらの演算結果やメソッドで処理した結果などを新たな列として追加できる。

df['F'] = df['B'] + df['C']
df['G'] = df['B'].str.lower()
print(df)
#        A   B   C  D  E     F   G
# ONE    0  B1  C1  0  0  B1C1  b1
# TWO    0  B2  C2  0  1  B2C2  b2
# THREE  0  B3  C3  0  2  B3C3  b3

pandas.Seriesのラベルindexpandas.DataFrameの列名indexと一致していない場合は欠損値NaNが代入される。

s = pd.Series(['X2', 'X3', 'X4'], index=['TWO', 'THREE', 'FOUR'], name='X')
print(s)
# TWO      X2
# THREE    X3
# FOUR     X4
# Name: X, dtype: object

df['H'] = s
print(df)
#        A   B   C  D  E     F   G    H
# ONE    0  B1  C1  0  0  B1C1  b1  NaN
# TWO    0  B2  C2  0  1  B2C2  b2   X2
# THREE  0  B3  C3  0  2  B3C3  b3   X3

pandas.Seriesvalues属性でNumPy配列numpy.ndarrayを取得して代入するとindexに関係なく要素が順番に代入される。この場合、要素数が行数と一致していないとエラーになる。

print(s.values)
# ['X2' 'X3' 'X4']

df['I'] = s.values
print(df)
#        A   B   C  D  E     F   G    H   I
# ONE    0  B1  C1  0  0  B1C1  b1  NaN  X2
# TWO    0  B2  C2  0  1  B2C2  b2   X2  X3
# THREE  0  B3  C3  0  2  B3C3  b3   X3  X4

assign()メソッドで追加・代入

pandas.DataFrameに新たな列を追加したり既存の列に新たな値を代入したりするためのメソッドとしてassign()が用意されている。

assign()メソッドでは、キーワード引数列名=値で列名とその値を指定する。

既存の列名の場合は値が代入され、新規の列名の場合は新たな列が追加される。

df = pd.DataFrame({'A': ['A1', 'A2', 'A3'],
                   'B': ['B1', 'B2', 'B3'],
                   'C': ['C1', 'C2', 'C3']},
                  index=['ONE', 'TWO', 'THREE'])

print(df.assign(A=0))
#        A   B   C
# ONE    0  B1  C1
# TWO    0  B2  C2
# THREE  0  B3  C3

print(df.assign(D=0))
#         A   B   C  D
# ONE    A1  B1  C1  0
# TWO    A2  B2  C2  0
# THREE  A3  B3  C3  0

新たなオブジェクトが返され、元のオブジェクトは変更されない。

print(df)
#         A   B   C
# ONE    A1  B1  C1
# TWO    A2  B2  C2
# THREE  A3  B3  C3

上述の[列名]で追加する例のように、リストやpandas.Seriesなども指定可能。キーワード引数を複数指定して複数列を一括で追加・代入することもできる。

s = pd.Series(['X2', 'X3', 'X4'], index=['TWO', 'THREE', 'FOUR'], name='X')
print(s)
# TWO      X2
# THREE    X3
# FOUR     X4
# Name: X, dtype: object

df_new = df.assign(C='XXX',
                   D=0, E=[0, 1, 2],
                   F=s, G=s.values,
                   H=df['A'] + df['B'])
print(df_new)
#         A   B    C  D  E    F   G     H
# ONE    A1  B1  XXX  0  0  NaN  X2  A1B1
# TWO    A2  B2  XXX  0  1   X2  X3  A2B2
# THREE  A3  B3  XXX  0  2   X3  X4  A3B3

なお、assign()メソッドを使う場合、列名がPythonの文法において引数名として使えるものに限定されるので注意。数値から始まる名前や、アンダースコア_以外の記号を含む名前、予約語などはエラーになる。Pythonで引数名として使える名前については以下の記事を参照。

insert()メソッドで任意の位置に追加

[列名]指定やassign()メソッドでは元のpandas.DataFrameの末尾(右側)に新たな列が追加されるが、insert()メソッドを使うと任意の位置に列を追加できる。

第一引数に位置、第二引数に列名、第三引数に追加する値を指定する。

第三引数にはスカラー値やリストなどのarray-likeオブジェクト、pandas.Seriesを指定可能。考え方はこれまでの例と同じ。

元のDataFrame自体が更新される。

df = pd.DataFrame({'A': ['A1', 'A2', 'A3'],
                   'B': ['B1', 'B2', 'B3'],
                   'C': ['C1', 'C2', 'C3']},
                  index=['ONE', 'TWO', 'THREE'])
s = pd.Series(['X2', 'X3', 'X4'], index=['TWO', 'THREE', 'FOUR'], name='X')

df.insert(0, 'D', 0)
print(df)
#        D   A   B   C
# ONE    0  A1  B1  C1
# TWO    0  A2  B2  C2
# THREE  0  A3  B3  C3

df.insert(len(df.columns), 'E', s)
print(df)
#        D   A   B   C    E
# ONE    0  A1  B1  C1  NaN
# TWO    0  A2  B2  C2   X2
# THREE  0  A3  B3  C3   X3

第一引数に行数を超える値を指定するとエラー。負の値で後ろからの位置を指定することもできない。末尾はlen(df.columns)df.shape[1]などで行数を取得して指定すればよい。

# df.insert(10, 'F', 10)
# ValueError: cannot insert F, already exists

# df.insert(-1, 'F', 10)
# ValueError: unbounded slice

第二引数に既に存在する列名を指定するとエラー。引数allow_duplicatesTrueとすると追加可能だが、列名が重複してしまうのでおすすめしない。

# df.insert(0, 'D', 10)
# ValueError: cannot insert D, already exists

df.insert(0, 'D', 10, allow_duplicates=True)
print(df)
#         D  D   A   B   C    E
# ONE    10  0  A1  B1  C1  NaN
# TWO    10  0  A2  B2  C2   X2
# THREE  10  0  A3  B3  C3   X3

concat()関数でSeries, DataFrameを横に連結

これまでの例ではpandas.Seriesを追加する場合、そのname属性は無視された。

pandas.concat()関数で引数axis=1として横方向に連結すると、pandas.Seriesnamepandas.DataFrameの列名となる。

pandas.concat()の第一引数に連結したいオブジェクトを要素とするリストやタプルを指定する。

df = pd.DataFrame({'A': ['A1', 'A2', 'A3'],
                   'B': ['B1', 'B2', 'B3'],
                   'C': ['C1', 'C2', 'C3']},
                  index=['ONE', 'TWO', 'THREE'])
s = pd.Series(['X2', 'X3', 'X4'], index=['TWO', 'THREE', 'FOUR'], name='X')

print(pd.concat([df, s], axis=1))
#          A    B    C    X
# ONE     A1   B1   C1  NaN
# TWO     A2   B2   C2   X2
# THREE   A3   B3   C3   X3
# FOUR   NaN  NaN  NaN   X4

引数join='inner'として共通の行名の行のみを残すことも可能。

print(pd.concat([df, s], axis=1, join='inner'))
#         A   B   C   X
# TWO    A2  B2  C2  X2
# THREE  A3  B3  C3  X3

複数のpandas.Seriesを連結したり、pandas.DataFrameを連結したりすることもできる。

s1 = pd.Series(['X1', 'X2', 'X3'], index=df.index, name='X')
s2 = pd.Series(['Y1', 'Y2', 'Y3'], index=df.index, name='Y')

print(pd.concat([df, s1, s2], axis=1))
#         A   B   C   X   Y
# ONE    A1  B1  C1  X1  Y1
# TWO    A2  B2  C2  X2  Y2
# THREE  A3  B3  C3  X3  Y3

df2 = pd.DataFrame({'df_col1': 0, 'df_col2': range(3)}, index=df.index)
print(df2)
#        df_col1  df_col2
# ONE          0        0
# TWO          0        1
# THREE        0        2

print(pd.concat([df, df2], axis=1))
#         A   B   C  df_col1  df_col2
# ONE    A1  B1  C1        0        0
# TWO    A2  B2  C2        0        1
# THREE  A3  B3  C3        0        2

pandas.concat()関数についての詳細は以下の記事を参照。

pandas.DataFrameに行を追加

新規行名を指定して追加

iloc[行名]で行を選択して値を代入できる。

df = pd.DataFrame({'A': ['A1', 'A2', 'A3'],
                   'B': ['B1', 'B2', 'B3'],
                   'C': ['C1', 'C2', 'C3']},
                  index=['ONE', 'TWO', 'THREE'])
print(df)
#         A   B   C
# ONE    A1  B1  C1
# TWO    A2  B2  C2
# THREE  A3  B3  C3

df.loc['ONE'] = 0
print(df)
#         A   B   C
# ONE     0   0   0
# TWO    A2  B2  C2
# THREE  A3  B3  C3

列の場合と同様に、ここにまだ存在しない行名を指定することで、その行を追加して値を代入することができる。

考え方は列の場合と同じ。スカラー値やリストなどのarray-likeオブジェクトを追加できる。

df.loc['FOUR'] = 0
df.loc['FIVE'] = ['A5', 'B5', 'C5']
print(df)
#         A   B   C
# ONE     0   0   0
# TWO    A2  B2  C2
# THREE  A3  B3  C3
# FOUR    0   0   0
# FIVE   A5  B5  C5

array-likeオブジェクトの場合、要素数と列数が一致していないとエラー(ValueError)になる。

# df.loc['SIX'] = ['A6', 'B6']
# ValueError: cannot set a row with mismatched columns

pandas.Seriesも列の場合と同様。ラベルが一致しないときは欠損値NaNが代入される。ラベルを無視したい場合はvaluesnumpy.ndarrayとする。

s = pd.Series(['B6', 'C6', 'D6'], index=['B', 'C', 'D'], name='SIX')
print(s)
# B    B6
# C    C6
# D    D6
# Name: SIX, dtype: object

df.loc['XXX'] = df.loc['TWO'] + df.loc['THREE']
df.loc['YYY'] = s
df.loc['ZZZ'] = s.values
print(df)
#           A     B     C
# ONE       0     0     0
# TWO      A2    B2    C2
# THREE    A3    B3    C3
# FOUR      0     0     0
# FIVE     A5    B5    C5
# XXX    A2A3  B2B3  C2C3
# YYY     NaN    B6    C6
# ZZZ      B6    C6    D6

append()メソッドで追加

pandas.DataFrameに新たな行を追加するために、append()メソッドが用意されている。

第一引数に追加するオブジェクトを指定する。

第一引数に指定できるのは基本的にpandas.Seriespandas.DataFrame、および、それらを要素とするリストやタプル。

スカラー値やリストなどを指定するとエラーになったり、想定外の結果になったりする。辞書で指定することも可能だがあまり実用的ではないだろう。

df = pd.DataFrame({'A': ['A1', 'A2', 'A3'],
                   'B': ['B1', 'B2', 'B3'],
                   'C': ['C1', 'C2', 'C3']},
                  index=['ONE', 'TWO', 'THREE'])

# print(df.append(0))
# TypeError: cannot concatenate object of type '<class 'int'>'; only Series and DataFrame objs are valid

print(df.append([0, 1, 2]))
#          A    B    C    0
# ONE     A1   B1   C1  NaN
# TWO     A2   B2   C2  NaN
# THREE   A3   B3   C3  NaN
# 0      NaN  NaN  NaN  0.0
# 1      NaN  NaN  NaN  1.0
# 2      NaN  NaN  NaN  2.0

print(df.append({'A': 0, 'B': 1, 'C': 2}, ignore_index=True))
#     A   B   C
# 0  A1  B1  C1
# 1  A2  B2  C2
# 2  A3  B3  C3
# 3   0   1   2

第一引数にpandas.Seriesを指定する場合、元のpandas.DataFrameの列名columnspandas.Seriesのラベルindexが対応する。一致しない場合は欠損値NaNが代入される。

pandas.Seriesname属性が新たな行名となる。

s = pd.Series(['A4', 'B4', 'C4'], index=df.columns, name='FOUR')

print(df.append(s))
#         A   B   C
# ONE    A1  B1  C1
# TWO    A2  B2  C2
# THREE  A3  B3  C3
# FOUR   A4  B4  C4

s_mismatch = pd.Series(['B5', 'C5', 'D5'], index=['B', 'C', 'D'], name='FIVE')

print(df.append(s_mismatch))
#          A   B   C    D
# ONE     A1  B1  C1  NaN
# TWO     A2  B2  C2  NaN
# THREE   A3  B3  C3  NaN
# FIVE   NaN  B5  C5   D5

新たなオブジェクトが返され、元のオブジェクトは変更されない。

print(df)
#         A   B   C
# ONE    A1  B1  C1
# TWO    A2  B2  C2
# THREE  A3  B3  C3

pandas.Seriesname属性が設定されていないとエラー。引数ignore_indexTrueとすると追加できるが、行名indexがすべて無視され0始まりの連番になる。

s_no_name = pd.Series(['B4', 'C4', 'D4'], index=['B', 'C', 'D'])

# print(df.append(s_no_name))
# TypeError: Can only append a Series if ignore_index=True or if the Series has a name

print(df.append(s_no_name, ignore_index=True))
#      A   B   C    D
# 0   A1  B1  C1  NaN
# 1   A2  B2  C2  NaN
# 2   A3  B3  C3  NaN
# 3  NaN  B4  C4   D4

第一引数にリストやタプルを指定すると、複数のオブジェクトを追加できる。

print(df.append([s, s_mismatch]))
#          A   B   C    D
# ONE     A1  B1  C1  NaN
# TWO     A2  B2  C2  NaN
# THREE   A3  B3  C3  NaN
# FOUR    A4  B4  C4  NaN
# FIVE   NaN  B5  C5   D5

pandas.DataFrameも指定可能。

df2 = pd.DataFrame([['B6', 'C6', 'D6'], ['B7', 'C7', 'D7']], 
                   index=['SIX', 'SEVEN'], columns=['B', 'C', 'D'])
print(df2)
#         B   C   D
# SIX    B6  C6  D6
# SEVEN  B7  C7  D7

print(df.append(df2))
#          A   B   C    D
# ONE     A1  B1  C1  NaN
# TWO     A2  B2  C2  NaN
# THREE   A3  B3  C3  NaN
# SIX    NaN  B6  C6   D6
# SEVEN  NaN  B7  C7   D7

pandas.DataFramepandas.Seriesが混在するリストはエラー。append()を繰り返し呼び出すのは問題ない。

# print(df.append([s, df2]))
# ValueError: all the input array dimensions for the concatenation axis must match exactly, but along dimension 1, the array at index 0 has size 5 and the array at index 1 has size 3

print(df.append(s).append(df2))
#          A   B   C    D
# ONE     A1  B1  C1  NaN
# TWO     A2  B2  C2  NaN
# THREE   A3  B3  C3  NaN
# FOUR    A4  B4  C4  NaN
# SIX    NaN  B6  C6   D6
# SEVEN  NaN  B7  C7   D7

concat()関数でSeries, DataFrameを縦に連結

pandas.DataFrame同士の連結はpandas.concat()関数でも可能。

pandas.concat()の第一引数に連結したいオブジェクトを要素とするリストやタプルを指定する。デフォルトで縦方向に連結される。

print(pd.concat([df, df2]))
#          A   B   C    D
# ONE     A1  B1  C1  NaN
# TWO     A2  B2  C2  NaN
# THREE   A3  B3  C3  NaN
# SIX    NaN  B6  C6   D6
# SEVEN  NaN  B7  C7   D7

引数join='inner'として共通の列名の列のみを残すことも可能。

print(pd.concat([df, df2], join='inner'))
#         B   C
# ONE    B1  C1
# TWO    B2  C2
# THREE  B3  C3
# SIX    B6  C6
# SEVEN  B7  C7

pandas.DataFramepandas.Seriesの縦方向の連結は注意が必要。

append()メソッドを使うと以下のように追加される。

print(df.append(s))
#         A   B   C
# ONE    A1  B1  C1
# TWO    A2  B2  C2
# THREE  A3  B3  C3
# FOUR   A4  B4  C4

一方、pandas.concat()関数の場合は以下のようになってしまう。

print(pd.concat([df, s]))
#          A    B    C    0
# ONE     A1   B1   C1  NaN
# TWO     A2   B2   C2  NaN
# THREE   A3   B3   C3  NaN
# A      NaN  NaN  NaN   A4
# B      NaN  NaN  NaN   B4
# C      NaN  NaN  NaN   C4

pandas.Seriesからpandas.DataFrameを生成しさらに転置すればpandas.concat()で連結できるが、append()メソッドを使うほうが素直だろう。

print(pd.DataFrame(s).T)
#        A   B   C
# FOUR  A4  B4  C4

print(pd.concat([df, pd.DataFrame(s).T]))
#         A   B   C
# ONE    A1  B1  C1
# TWO    A2  B2  C2
# THREE  A3  B3  C3
# FOUR   A4  B4  C4

pandas.concat()関数についての詳細は以下の記事を参照。

転置してからassign(), insert()メソッドを使用

行の追加にもassign()メソッドを使用したい場合は、pandas.DataFrameを転置してからassign()メソッドを使用し、さらに転置してもとに戻すという方法も可能。あまり良い方法ではないかもしれない。

print(df.T.assign(FOUR=0, FIVE=['A5', 'B5', 'C5']).T)
#         A   B   C
# ONE    A1  B1  C1
# TWO    A2  B2  C2
# THREE  A3  B3  C3
# FOUR    0   0   0
# FIVE   A5  B5  C5

同様にinsert()メソッドを用いることもできるが、insert()は元のpandas.DataFrame自体を更新するためメソッドチェーンでは書けない。要注意。

# df_insert = df.T.insert(0, 'FOUR', 0).T
# AttributeError: 'NoneType' object has no attribute 'T'

df_T = df.T
df_T.insert(0, 'FOUR', 0)
print(df_T.T)
#         A   B   C
# FOUR    0   0   0
# ONE    A1  B1  C1
# TWO    A2  B2  C2
# THREE  A3  B3  C3
スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事