最終更新日:2021/8/26

dfどうしの結合、連結の方法を説明します。ここでは、特に縦方向(行方向)への結合、連結を扱います。
このページでは、「結合」と「連結」はほぼ同じ意味で用いています。
幾つか方法がありますが、ここでは、目的への一番の近道と思われる方法だけを扱います。

【説明すること】

1. はじめに

縦方向(行方向)への結合・連結は、欠損値が生じないようにする為には、基本的には元のdfと、追加するdfで、同じカラム名(列名)を持っていなければなりません
例えば、Excelのように1-5行目と6-10行目で違うカラム名のものを結合する、というのは簡単にはできません。
また、indexとカラム名(列名)を常に意識することが重要です。
カラム名、indexを意識する、ということはlistでは結合ができず、基本的にはDataFrame(df)かSeries(se)を結合・連結の対象に扱うことになります。
なぜならば、listにはそれらの考え方が無いからです。
尚、縦への結合は1行を追加する、という操作にも応用できます

2. df+dfの結合 : pd.concat()

dfにdfを結合する場合、

pd.concat([df1, df2], axis=0, ignore_index=True)

を使います。

axis=0は方向を指定するオプションで、縦方向(行方向)という意味で、よく使います。
他にaxis=1があり、これは横方向(列方向)という意味です。

また、ignore_index=Trueは、結合したdfのindexを振り直します。振り直す必要がない場合は、省略できます。または、ignore_index=Falseを指定します。

・カラム名(列名)が一致しない場合
結合の対象とするdf1とdf2のカラム名が一致しない場合、結合したdfに、不一致なカラムが追加されます。

以下のcsvファイルを読み込んで例を挙げます。

a004_010a_a.csv, a004_010a_b.csv, a004_010a_c.csv

import pandas as pd
f1a = r'C:\Users\shilabo\Documents\SHiLABO_python\a004_010a_a.csv'
f1b = r'C:\Users\shilabo\Documents\SHiLABO_python\a004_010a_b.csv'
f1c = r'C:\Users\shilabo\Documents\SHiLABO_python\a004_010a_c.csv'
df1a = pd.read_csv(f1a)
df1b = pd.read_csv(f1b)
df1c = pd.read_csv(f1c)
print(df1a)
# clm0 clm1
#0 A0 B0
#1 A1 B1
print(df1b)
# clm0 clm1
#0 a0 b0
#1 a1 b1
print(df1c)
# clm0 clm1 clm90
#0 a0 b0 x0
#1 a1 b1 x1
#1. .concat[df, df]
df2ab = pd.concat([df1a, df1b], axis=0)
print(df2ab)
# clm0 clm1
#0 A0 B0
#1 A1 B1
#0 a0 b0
#1 a1 b1
# ignore_index = True
df2abT = pd.concat([df1a, df1b], axis=0, ignore_index=True)
print(df2abT)
# clm0 clm1
#0 A0 B0
#1 A1 B1
#2 a0 b0
#3 a1 b1
df2ac = pd.concat([df1a, df1c], axis=0) #カラム名が一致しない場合。
print(df2ac)
# clm0 clm1 clm90
#0 A0 B0 NaN
#1 A1 B1 NaN
#0 a0 b0 x0
#1 a1 b1 x1

3. df+seの結合 : df.append(se)

dfとseを結合する場合は、

df.append(se, ignore_index=True)

と書きます。ignore_index=Trueは、上記2.と同じで、結合したdfのindexを振り直します。振り直す必要がない場合は、省略できます。

結合するseのindex(seにカラム名は無い)が、対象のdfのカラム名と一致するか、で分けておきます。理屈は同じですが、違いをはっきりさせる為です。

3.1. seのindexがdfのカラム名と一致する場合
3.2. seのindexがdfのカラム名と一致しない場合


他にも、pd.concat([df, se])を使う方法などがありますが、多くの場合、必要とする結果はdf.append()だと思います。
これ以外は、複雑なので、ここでは省略します。

尚、seはdfの1列を抜き出したものでもあるので、dfに1行を追加する場合も、この操作で実現します。
コードを書く際は、indexとカラム名を意識してください

3.1. seのindexがdfのカラム名と一致する場合

df.append(se, ignore_index=True)

と書きます。ignore_index=Trueは、前出の通りです。

この場合、dfの一番下にseが追加されます。seが横向きで下に追加されるイメージで、行の追加という感じです。そして、結合後のdfのindex名がseのnameになります。
これが、多くのケースで必要とされる結果だと思います。
繰り返しになりますが、indexとカラム名、そしてseのnameを意識する事がとても重要です。

・結合後のdfのindex名(縦方向のラベル) = seのname
・結合後のdfのカラム名(横方向のラベル) = seのindex名 = もとのdfのカラム名

#(1)seのindexが一致する場合
#df1cからseriesにして、カラム名を同じにする
se3a = df1c['clm90'].copy()
se3a.index = ['clm0', 'clm1']
print(se3a)
#clm0 x0
#clm1 x1
#Name: clm90, dtype: object
df3a = df1a.append(se3a)
print(df3a)
# clm0 clm1
#0 A0 B0
#1 A1 B1
#clm90 x0 x1 #<=横向きで最終行へ


他のdfから1行をコピーして張り付ける場合は、以下のようになります。

#例: 他の1行をコピーして下に貼付け
se3c = df1b.iloc[0,:] #<=0行目だけ。これはSeries。
print(se3c)
#clm0 a0
#clm1 b0
#Name: 0, dtype: object
df3c = df1a.append(se3c)
print(df3c)
# clm0 clm1
#0 A0 B0
#1 A1 B1
#0 a0 b0

3.2. seのindexがdfのカラム名と一致しない場合

同じく、

df.append(se, ignore_index=True)

と書きます。ignore_index=Trueは、前出の通りです。

この場合、カラムが追加され、そのカラム名がseのindex名となります。seが横向きで右にとって付けるイメージです。結合した結果のdfのindex名がseのnameになります。

結合後のdfのindex名(縦方向のラベル) = seのname
結合後のdfのカラム名(横方向のラベル) = もとのdfのカラム名 + 不一致なseのindex名

#(2)seのindexが一致しない場合
#df1cからseriesにして、カラム名を異なるものにする。
se3b = df1c['clm90'].copy()
se3b.index = [10, 11]
#これは、以下と同じこと。
#se3b = pd.Series(['x0', 'x1'], index=[10, 11], name='clm90')
print(se3b)
#10 x0
#11 x1
#Name: clm90, dtype: object  #<= 「name='clm90'」に注目
df3a = df1a.append(se3b)
print(df3a)
# clm0 clm1 10 11
#0 A0 B0 NaN NaN
#1 A1 B1 NaN NaN
#clm90 NaN NaN x0 x1 #<=これがse3b

参考HP

以下のHPがとても詳しいので、参考にしてください。図があって、とても分かりやすいです。
https://sinhrks.hatenablog.com/entry/2015/01/28/073327