pandas

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

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

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

SeriesやDataFrameの連結方法

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

pandasで中心的なデータ構造はSeriesやDataFrameです。これらは連結処理を念頭に置いて設計されているため、データを簡単に連結することができます。具体的には、pandasのSeriesやDataFrameを連結したい場合、concat関数を使用することができます。

この記事では、pandasの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_integrityignore_indexを使った対処法があります。

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

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

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

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_integrityTrueに設定すると、インデックスが重複していた場合には、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関数を使用するよう警告が表示される場合があります。

appendメソッドは使用可能な場合であっても、データ連結の際はconcat関数の使用を推奨します。

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

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

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

まとめ

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

データ分析では、単にデータを連結するだけではなく、重複するデータの適切な処理や、連結時に元のデータを保持しながら階層型インデックス(マルチインデックス)を作成する方法、さらにouterinner結合を使い分けることが重要です。これらについて本記事で紹介しました。

データ分析においては、複数のデータソースを適切に結合してから分析を行うことで、有益な情報を抽出できます。concat関数を利用したデータ結合に慣れることは重要です。