pandas

【pandas】列名に特定の文字列を含まない列を抽出する【Python】

MAX

列名に特定の文字列を含む列を抽出するのは簡単だが、特定の文字列を含まない文字列を抽出する場合、単純にはいかない。

列名に特定の文字列を含まない列を抽出する方法はfilterと正規表現の否定先読み、否定後読みを使うことでできる。

スポンサーリンク

データ作成

以下のように列名とインデックスを持つDataFrameを作成する。

1import pandas as pd
2
3data = [[1, 2, 3, 4, 5], [2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [8, 9, 10, 11, 12]]
4columns = ["colA", "colB", "col_C", "列D", "列_E"]
5index = ["indexA", "indexB", "index_C", "index_d"]
6df = pd.DataFrame(data=data, columns=columns, index=index)
7print(df)
8#             colA  colB  col_C  列D  列_E
9# indexA      1      2         3     4       5
10# indexB      2      3         4     5       6
11# index_C    3      4         5     6       7
12# index_d    8      9       10   11     12

列名に特定の文字列を含まない列を抽出したい場合、特定の文字列が「先頭」「文中」「末尾」のどこに含まれるかによって指定方法が異なる。

正規表現の基本

re-正規表現操作

本記事で使用する正規表現は以下の通り。

特殊文字意味
^先頭
$末尾
.(ドット)任意の1文字
*直前の正規表現をできるだけ多く繰り返したものにマッチ
\w任意の1文字と_(アンダースコア)にマッチ
1# 先頭が「col」で始まる文字列にマッチするパターン
2"^col.*"
3
4# 末尾が「_1文字」で終わる文字列にマッチするパターン
5".*_\w$"

列名が特定の文字列で始まらない列を抽出

否定先読みは(?!マッチさせたくない文字列)で作成する。

マッチさせたくない文字列が先頭からの場合、"^(?!マッチさせたくない文字列).*"で抽出可能。

1# 列名がcolで始まらない列を抽出
2df_filter = df.filter(regex="^(?!col).*")
3print(df_filter)
4#              列D  列_E
5# indexA     4       5
6# indexB     5       6
7# index_C   6       7
8# index_d  11    12

filterのregexに"^(?!col).*"と指定することで、「col」から始まる列以外を抽出できる。

列名が特定の文字列で終わらない列を抽出

特定の文字列で終わらない列名を抽出したい場合は否定後読みという指定方法を使う。

(?<!マッチさせたくない文字列)が否定後読みとなる。

具体的な例は以下の通り。

1# 列名が_1文字で終わらない列を抽出
2df_filter = df.filter(regex="^.*(?<!_\w)$")
3print(df_filter)
4#             colA  colB  列D
5# indexA      1      2     4
6# indexB      2      3     5
7# index_C    3      4     6
8# index_d    8      9   11

(?<!_\w)$は末尾が「_1文字」で終わらないことを意味する。

^.*は先頭からの任意の文字列を意味する。

列名が特定の文字列を含まない列を抽出

列名の真ん中に特定の文字列が含まれない列を抽出したい場合は、否定先読みを使う。

.*」は任意の文字列を表すが、否定先読みの中に「.*」を入れることで、文中の特定の文字列を表せる。

1# 列名に「ol」が含まれない列を抽出
2df_filter = df.filter(regex="^(?!.*ol).*$")
3print(df_filter)
4#              列D  列_E
5# indexA     4       5
6# indexB     5       6
7# index_C   6      7
8# index_d  11    12

列名に特定の文字列を含む列を抽出

列名に特定の文字列を含む列を抽出する場合、likeという引数も使えるため、likeで抽出できるものはlikeで抽出すると楽。

filterのlikeを使う方法

指定した文字列が含まれる列をlikeで抽出

1# likeを指定することで、指定した文字列を含む列を抽出できる
2df_filter = df.filter(like="ol")
3print(df_filter)
4#             colA  colB  col_C
5# indexA      1      2         3
6# indexB      2      3         4
7# index_C    3      4         5
8# index_d    8      9       10

対象の列がない場合はエラーではなくemptyが返ってくる

1# 指定した文字が含まれる列がない場合、indexのみのDFが返ってくる
2df_filter = df.filter(like="a")
3print(df_filter)
4# Empty DataFrame
5# Columns: []
6# Index: [indexA, indexB, index_C, index_d]

抽出対象となる列がなかった場合、エラーではなくindexだけのDataFrameが返ってくる。

indexに対しても抽出可能

1# 明示的にaxisを指定することでindexに対してもlikeでの抽出を行える
2df_filter = df.filter(like="index_", axis=0)
3print(df_filter)
4#              colA  colB  col_C  列D  列_E
5# index_C     3      4         5     6       7
6# index_d     8      9       10   11     12

引数のaxisに0を指定することでindexに対しての抽出も行える。

filterのregexを使う方法

否定先読み、否定後読みを使わずに、正規表現にマッチする列を抽出する例。

1# 列名が2文字か3文字の列を抽出
2df_filter = df.filter(regex="^\w{2,3}$")
3print(df_filter)
4#              列D  列_E
5# indexA     4       5
6# indexB     5       6
7# index_C   6       7
8# index_d  11    12

まとめ

否定先読み、否定後読みを使うことで、「特定の文字列にマッチしない」を表現できる。

1# 列名がcolで始まらない列を抽出
2df_filter = df.filter(regex="^(?!col).*")
3
4# 列名が_1文字で終わらない列を抽出
5df_filter = df.filter(regex="^.*(?<!_\w)$")
6
7# 列名に「ol」が含まれない列を抽出
8df_filter = df.filter(regex="^(?!.*ol).*$")

スポンサーリンク
ABOUT ME
MAX
MAX
ITエンジニア、データサイエンティスト
新卒でSIerに入社し、フリーランスになってWEB系へ転向。
その後AIの世界へ足を踏み入れ、正社員に戻る。 テーブルデータの分析がメイン。
スポンサーリンク
記事URLをコピーしました