pandas

【Pandas】DataFrame内で重複する列名を削除する【Python】

MAX

複数のDataFrameを結合していると、列名が重複してしまう場合がある。

マージの場合、マージ時に列名が重複する場合、自動でサフィックスが付加される(手動でも設定できる)。

マージは2つのDataFrameを結合する際に非常に便利な関数だが、結合キーがindexで複数のDataFrameをまとめて結合したい場合、concatを使う方がラクにできる。

concatでの結合時に列名が重複した場合、削除するかサフィックスなどを付加するかが必要となる(列名が重複したままで操作を行うと、想定外のことが起こりやすい)

スポンサーリンク

データ作成

concatを使って重複している列名を持つDataFrameを作成する。

1# データ作成
2df1 = pd.DataFrame(data={
3    "A": [1, 2, 3],
4    "B": [4, 5, 6],
5    "C": [7, 8, 9],
6})
7df2 = pd.DataFrame(data={
8    "B": [1, 2, 3],
9    "C": [2, 3, 4],
10    "D": [3, 4, 5]
11})
12df3 = pd.DataFrame(data={
13    "C": [1, 2, 3],
14    "E": [2, 3, 4]
15})
16df = pd.concat([df1, df2, df3], axis=1)
17print(df)
18#    A  B  C  B  C  D  C  E
19# 0  1  4  7  1  2  3  1  2
20# 1  2  5  8  2  3  4  2  3
21# 2  3  6  9  3  4  5  3  4

B列が2回、C列が3回登場する。

DataFrame内で重複している列名を確認する

DataFrame.columnsに対してduplicated()を使うことで重複の確認ができる。

duplicated()を使う重複確認

1# 列名が重複しているかを確認する
2# 最初に出現した列はFalseとなり、2回目以降同じ列名が出現した場合はTrueとなる
3is_duplicate_columns = df.columns.duplicated()
4print(is_duplicate_columns)
5# [False False False  True  True False  True False
6# 各True、Falseは以下の内容に対応
7#  A     B     C      B     C    D      C    E

2回目以降に登場したB、CにはTrueが立つ。それ以外はFalseとなる。

duplicated(keep=”last”)を使う重複確認

duplicatedの引数にkeep=”last”を指定することで、重複列のTrueとFalseを変えられる。

1# keep="last"を設定した場合、
2# 重複がある列のうち、最後に出現した列はFalseとなり、それ以前に出現した列はTrueとなる。
3is_duplicate_columns = df.columns.duplicated(keep="last")
4print(is_duplicate_columns)
5# [False  True  True False  True False False False]
6#  A     B     C      B     C    D      C    E

B、Cは複数回登場するが、最後のB、C以外にTrueが立つようになる。

これらを利用して重複する列を取得していく。

DataFrame内で重複している列名を取得する

1# 重複している列名を取得する
2# 今回の例の場合、Cが3列あり、そのうち2回分が重複している列として取得されるため、unique()も行う
3duplicate_columns = df.columns[df.columns.duplicated()].unique()
4print(duplicate_columns)
5# Index(['B', 'C'], dtype='object')
1# 重複している列名を取得する
2# 今回の例の場合、Cが3列あり、そのうち2回分が重複している列として取得されるため、unique()も行う
3duplicate_columns = df.columns[df.columns.duplicated(keep="last")].unique()
4print(duplicate_columns)
5# Index(['B', 'C'], dtype='object')

duplicated()で重複している列名のTrue、Falseのリストが得られるので、そのTrue・Falseのリストを使って列名を取得する。

3回以上登場する列名は重複している列名のリストにも2回以上登場することになるため、unique()で一意にする。

DataFrame内で重複している列を削除する

重複している列を削除したい場合、dropなどで削除するのではなく、重複していない列を取得する感じの処理になる。

重複する列のうち、最初の列以外を削除する

1# df.columns.duplicated()で、列名に重複がある場合、2回目以降の列にはTrueが立つ
2# ~で否定することで2回目以降の列がFalseになり、除外される
3df_keep_first = df.loc[:, ~df.columns.duplicated()]
4print(df_keep_first)
5#    A  B  C  D  E
6# 0  1  4  7  3  2
7# 1  2  5  8  4  3
8# 2  3  6  9  5  4

重複する列のうち、最後の列以外を削除する

keep=”last”にすることで、重複がある列は最後の列を保持するようになる。

1# duplicatedの引数にkeep=lastを設定することで、重複がある列の最後の列以外Trueが立つようになる
2# ~で否定することで、最後の列のみがTrueになる。
3df_keep_last = df.loc[:, ~df.columns.duplicated(keep="last")]
4print(df_keep_last)
5#    A  B  D  C  E
6# 0  1  1  3  1  2
7# 1  2  2  4  2  3
8# 2  3  3  5  3  4

DataFrame内で重複している列にサフィックスを付ける

1# 列名のSeriesを作成する
2cols = pd.Series(df.columns)
3# 重複する列目でループ
4for dup in cols[cols.duplicated()].unique(): 
5    cols[cols[cols == dup].index.values.tolist()] = [dup + '_' + str(i) if i != 0 else dup for i in range(sum(cols == dup))]
6df.columns = cols
7

3項演算子のif elseでi==0(重複列の最初に出現する列)の場合、サフィックスを付加しないようにしているが、どんなサフィックスを付加するかは、if-elseあたりを適当に修正すればOK。

ぱっと見では何してるのか分かりにくい。

プレフィックスやサフィックスを付ける場合、concat後ではなくconcat前に対応することも考えられる。

まとめ

1# 重複している列名を取得する
2duplicate_columns = df.columns[df.columns.duplicated()].unique()
3
4# 重複する列のうち、最初の列以外を除外する
5df_keep_first = df.loc[:, ~df.columns.duplicated()]
6
7# 重複する列のうち、最後の列以外を除外する
8df_keep_last = df.loc[:, ~df.columns.duplicated(keep="last")]
スポンサーリンク
ABOUT ME
MAX
MAX
ITエンジニア、データサイエンティスト
新卒でSIerに入社し、フリーランスになってWEB系へ転向。
その後AIの世界へ足を踏み入れ、正社員に戻る。 テーブルデータの分析がメイン。
スポンサーリンク
記事URLをコピーしました