pandas

【pandas】SeriesやDataFrameを連結する方法 ~concat, append~

【pandas】SeriesやDataFrameを連結する方法 _concat, append_

pandasのSeriesやDataFrameを連結する方法について解説します。

データ(SeriesやDataFrame)の連結方法

データ分析から得られる深い知見や興味深い研究成果というのは、異なる種類のデータソースの組み合わせからもたらされるものが多いです。ここでいう組み合わせというのは、2つのデータセットをただ連結するだけではなく、重複するデータを適切に処理する等も含まれます。

pandasのSeriesやDataFrameは、こういった種類の連結処理を意識して設計されているため、簡単にデータ連結するための関数やメソッドが用意されています。pandasのSeriesやDataFrameを単純に連結したい場合にはconcat関数やappendメソッドを使用することができます。

本記事では、pandasのconcat関数とappendメソッドの使用方法を中心に簡単な例を用いて使い方を紹介します。

concat関数によるデータの連結

concat関数の基本的な使い方

SeriesやDataFrameを連結する場合にはconcat関数を使用することができます。以下の簡単な例で見ていきましょう。

import pandas as pd

# ===== Seriesの連結
# データの準備
ser1 = pd.Series(['A', 'B', 'C', 'D', 'E'], index=[1, 2, 3, 4, 5])
ser2 = pd.Series(['V', 'W', 'X', 'Y', 'Z'], index=[6, 7, 8, 9, 10])

# 連結
ser_concat = pd.concat([ser1, ser2])
print(ser_concat, '\n')

# ===== DataFrameの連結
# データの準備
df1 = pd.DataFrame([['A', 'B'], ['C', 'D'], ['E', 'F']],
                   index=[1, 2, 3], columns=['attr1', 'attr2'])
df2 = pd.DataFrame([['U', 'V'], ['W', 'X'], ['Y', 'Z']],
                   index=[4, 5, 6], columns=['attr1', 'attr2'])

# 連結
df_concat = pd.concat([df1, df2])
print(df_concat)
【実行結果】
1     A
2     B
3     C
4     D
5     E
6     V
7     W
8     X
9     Y
10    Z
dtype: object 

  attr1 attr2
1     A     B
2     C     D
3     E     F
4     U     V
5     W     X
6     Y     Z

上記では、SeriesとDataFrameそれぞれ連結をしています。

使用方法は簡単で、concat関数の引数として連結したい対象のSeriesやDataFrameが含まれているリストを指定するだけです。

インデックスが重複している場合

concat関数の特徴として、連結するデータのインデックスが重複していてもそれぞれのインデックスが保持されるという点があります。以下はインデックスの2, 3が重複しているケースです。

import pandas as pd

# ===== DataFrameの連結
# データの準備
df1 = pd.DataFrame([['A', 'B'], ['C', 'D'], ['E', 'F']],
                   index=[1, 2, 3], columns=['attr1', 'attr2'])
df2 = pd.DataFrame([['U', 'V'], ['W', 'X'], ['Y', 'Z']],
                   index=[2, 3, 4], columns=['attr1', 'attr2'])

# 連結 (インデックスが重複していても保持する)
df_concat = pd.concat([df1, df2])
print(df_concat)
【実行結果】
  attr1 attr2
1     A     B
2     C     D
3     E     F
2     U     V
3     W     X
4     Y     Z

結果を見てもらえば分かりますが、2, 3がインデックスとして複数回出てきています。

このような状況でも問題がなければそのままで構いません。もし、重複があると問題になるような場合には、後述するverify_integrityやignore_indexを使った対処が使用できます。

重複がある場合に例外を出す ~ verify_integrity ~

concat関数はインデックスが重複していても保持する特徴がありました。もしインデックスが重複してしまうと問題がある場合の対処法として、重複がある場合に例外を出して対処する方法があります。

重複した場合に例外を出す場合には、以下のようにverify_integrityをTrueに設定します。

import pandas as pd

# ===== DataFrameの連結
df1 = pd.DataFrame([['A', 'B'], ['C', 'D'], ['E', 'F']],
                   index=[1, 2, 3], columns=['attr1', 'attr2'])
df2 = pd.DataFrame([['U', 'V'], ['W', 'X'], ['Y', 'Z']],
                   index=[2, 3, 4], columns=['attr1', 'attr2'])

# 連結 (インデックス重複時は例外:ValueError)
try:
    df_concat = pd.concat([df1, df2], verify_integrity=True)
    print(df_concat)
except ValueError as ex:
    print(ex)
【実行結果】
Indexes have overlapping values: Int64Index([2, 3], dtype='int64')

verify_integrityをTrueにしたときでインデックスが重複していた場合には「ValueError」の例外となります。この例外をキャッチすることで処理を変更するといった対処ができます。

インデックスを無視する ~ ignore_index ~

インデックスが重複しているケースで、もともとのインデックスは意味を持たない場合には、インデックスを無視してインデックスを振りなおすといったことが可能です。

インデックスを無視して振りなおす場合には、以下のようにignore_indexをTrueに設定します。

import pandas as pd

# ===== DataFrameの連結
df1 = pd.DataFrame([['A', 'B'], ['C', 'D'], ['E', 'F']],
                   index=[1, 2, 3], columns=['attr1', 'attr2'])
df2 = pd.DataFrame([['U', 'V'], ['W', 'X'], ['Y', 'Z']],
                   index=[2, 3, 4], columns=['attr1', 'attr2'])

# 連結 (インデックスを無視する)
df_concat = pd.concat([df1, df2], ignore_index=True)
print(df_concat)
【実行結果】
  attr1 attr2
0     A     B
1     C     D
2     E     F
3     U     V
4     W     X
5     Y     Z

上記結果を見てみると、もともとのインデックスは無視され、インデックスが新しく0から設定されてデータ連結されていることが分かります。

連結するデータにキーを指定して階層型インデックス(マルチインデックス)にする ~ keys ~

データを連結する際に、元のデータのキーを残して結合したい場合などには、階層型インデックス(マルチインデックス)にすることもできます。階層型インデックスにする場合には、以下のようにkeysで各データのキーとなる情報を指定します。

import pandas as pd

# ===== DataFrameの連結
# データの準備
df1 = pd.DataFrame([['A', 'B'], ['C', 'D'], ['E', 'F']],
                   index=[1, 2, 3], columns=['attr1', 'attr2'])
df2 = pd.DataFrame([['U', 'V'], ['W', 'X'], ['Y', 'Z']],
                   index=[2, 3, 4], columns=['attr1', 'attr2'])

# 連結 (階層型のインデックスにする)
df_concat = pd.concat([df1, df2], keys=['D1', 'D2'])
print(df_concat)
【実行結果】
     attr1 attr2
D1 1     A     B
   2     C     D
   3     E     F
D2 2     U     V
   3     W     X
   4     Y     Z

上記の例では’D1’、’D2’というものを指定しました。結果としては、それぞれ指定したキーの下の階層として元のデータのインデックスがあるような階層型のインデックスとなって連結されていることが分かるかと思います。

積集合での連結 ~ join=’inner’ ~

上記で見てきたデータでは列名が全く同じものを連結してきました。では、列名が異なっているデータを結合する場合はどのようになるのかを見てみましょう。

import pandas as pd

# ===== DataFrameの連結
df1 = pd.DataFrame([['A', 'B'], ['C', 'D'], ['E', 'F']],
                   index=[1, 2, 3], columns=['attr1', 'attr2'])
df2 = pd.DataFrame([['U', 'V'], ['W', 'X'], ['Y', 'Z']],
                   index=[4, 5, 6], columns=['attr2', 'attr3'])

# 連結 (デフォルトはjoin='outer')
df_concat = pd.concat([df1, df2])
print(df_concat, '\n')

# 連結 (join='inner')
df_concat = pd.concat([df1, df2], join='inner')
print(df_concat)
【実行結果】
  attr1 attr2 attr3
1     A     B   NaN
2     C     D   NaN
3     E     F   NaN
4   NaN     U     V
5   NaN     W     X
6   NaN     Y     Z 

  attr2
1     B
2     D
3     F
4     U
5     W
6     Y

concat関数は、デフォルトではjoin=’outer’となっています。outerとは和集合を意味するのでどちらの列も含んだ連結となり、値がない部分は上記結果例のようにNaNとなります。

もし、それぞれのデータのどちらにもある列のみを連結したい場合は、join=’inner’とすることで積集合として連結します。上記の結果例で見てみると、join=’inner’を指定した場合は、どちらにもある’attr2’列のみ連結したデータが返ってきていることが分かります。

Note

concat関数の公式ドキュメントはこちらを参照してください。

appendメソッドによるデータ連結【非推奨】

appendメソッドは、1.4.0から非推奨になっており、将来的にはpandasから削除されるようです。実行してみるとconcatを使うようにといった警告が出ます。本記事では参考として紹介しますが、データ連結の際は、concatを使用するようにしましょう。

SeriesやDataFrameはいずれもappendメソッドを持っているため、より簡潔にデータの連結をすることができます。以下の例で見てみましょう。

import pandas as pd

# ===== Seriesの連結
# データの準備
ser1 = pd.Series(['A', 'B', 'C', 'D', 'E'], index=[1, 2, 3, 4, 5])
ser2 = pd.Series(['V', 'W', 'X', 'Y', 'Z'], index=[6, 7, 8, 9, 10])

# 連結
print(ser1.append(ser2), '\n')

# ===== DataFrameの連結
# データの準備
df1 = pd.DataFrame([['A', 'B'], ['C', 'D'], ['E', 'F']],
                   index=[1, 2, 3], columns=['attr1', 'attr2'])
df2 = pd.DataFrame([['U', 'V'], ['W', 'X'], ['Y', 'Z']],
                   index=[4, 5, 6], columns=['attr1', 'attr2'])

# 連結
print(df1.append(df2))
【実行結果】
1     A
2     B
3     C
4     D
5     E
6     V
7     W
8     X
9     Y
10    Z
dtype: object 

  attr1 attr2
1     A     B
2     C     D
3     E     F
4     U     V
5     W     X
6     Y     Z

上記の例は、concat関数によって連結してきた例と全く同じデータです。

appendはメソッドのため、結合する片方のデータのメソッドを呼び出して引数として連結するデータを指定します。このようにappendメソッドでも同様にデータの連結が可能です。

pandasのappendメソッドは、元のオブジェクトを変更しているわけではなく、結合したデータで新しいデータが作成されていることに注意してください。

Note

appendメソッドの公式ドキュメントは、SeriesのメソッドDataFrameのメソッドを参照してください。

その他のデータの結合方法(merge, join)

上記では、concat関数とappendメソッド連結方法について紹介してきました。pandasには他にもmerge関数やjoinメソッドという強力なデータ結合方法があります。

データベースのSQLに慣れている人は、merge関数やjoinメソッドの理解がしやすいかもしれません。merge関数やjoinメソッドの使用方法については「DataFrameを結合する方法」でまとめていますので興味があれば参考にしてください。

まとめ

pandasのSeriesやDataFrameを連結する方法について解説しました。具体的には、concat関数とappendメソッドによるデータ連結方法について中心に説明しました。

データ分析では、ただデータを連結すればよいというわけではありません。本記事では、データのインデックスが重複している場合の処理方法、連結時に元のデータを残して階層型インデックス(マルチインデックス)を作る方法、outer/innerの結合の使い分けについても紹介しています。

データ分析では複数のデータソースを適切に連結してから分析することで有益な情報を抽出しやすくなります。concat関数を利用したデータ結合に慣れていただきたいと思います。

appendメソッドは、1.4.0から非推奨になっており、将来的にはpandasから削除されるようです。実行してみるとconcatを使うようにといった警告が出ます。本記事では参考として紹介しますが、データ連結の際は、concatを使用するようにしましょう。