note.nkmk.me

pandasの文字列から正規表現で抽出して新たな列を生成

Date: 2018-04-09 / tags: Python, pandas

文字列を要素とするpandas.DataFrameの列、pandas.Seriesから正規表現で特定の文字列を抽出して新たな列を生成する方法を説明する。

以下の文字列メソッドを使う。

  • str.extract(): 最初のマッチ部分のみ抽出
  • str.extractall(): すべてのマッチ部分を抽出

以下のpandas.Seriesを例とする。

import pandas as pd

s_org = pd.Series(['aaa@xxx.com', 'bbb@yyy.net', 'ccc@zzz.co.jp'], index=['A', 'B', 'C'])
print(s_org)
# A      aaa@xxx.com
# B      bbb@yyy.net
# C    ccc@zzz.co.jp
# dtype: object

pandas.DataFrameの列から抽出したい場合はdf['列名']のように列(= pandas.Series)を指定してstr.extract()str.extractall()を呼べばOK。

文字列の位置・長さを指定して抽出する場合はスライスを使うと簡単。以下の記事を参照。

スポンサーリンク

str.extract(): 最初のマッチ部分のみ抽出

正規表現の最初のマッチ部分のみ抽出するにはstr.extract()メソッドを使う。

str.extract()の第一引数に正規表現パターンを指定すると() で囲まれたグループ部分にマッチする文字列が抽出される。

引数expandTrueとするとpandas.DataFrameFalseとするとpandas.Seriesとして新たなオブジェクトが生成される。

df_single = s_org.str.extract('(.+)@', expand=True)
print(df_single)
print(type(df_single))
#      0
# A  aaa
# B  bbb
# C  ccc
# <class 'pandas.core.frame.DataFrame'>

s = s_org.str.extract('(.+)@', expand=False)
print(s)
print(type(s))
# A    aaa
# B    bbb
# C    ccc
# dtype: object
# <class 'pandas.core.series.Series'>

現在のバージョン0.22.0ではexpand=Falseがデフォルトだが、将来的にはexpand=Trueがデフォルトになるとのこと。

FutureWarning: currently extract(expand=None) means expand=False (return Index/Series/DataFrame)
but in a future version of pandas this will be changed to expand=True (return DataFrame)

正規表現パターンに名前付きグループ(?P<name>...)を使うと名前がそのまま列名(カラム名)になる。

df_name = s_org.str.extract('(?P<local>.+)@', expand=True)
print(df_name)
print(type(df_name))
#   local
# A   aaa
# B   bbb
# C   ccc
# <class 'pandas.core.frame.DataFrame'>

()で囲まれたグループが複数あると、各グループで抽出された部分がそれぞれ列となるpandas.DataFrameが返る。引数expandTrueでもFalseでもpandas.DataFrame

df_multi = s_org.str.extract('(?P<local>.+)@(?P<domain>.+)', expand=True)
print(df_multi)
#   local     domain
# A   aaa    xxx.com
# B   bbb    yyy.net
# C   ccc  zzz.co.jp

なお、この例の場合はstr.split()メソッドで区切り文字を@として分割することも可能。文字列の分割については以下の記事を参照。

マッチする部分がない場合はNaNとなる。

df_nan = s_org.str.extract('(a+)', expand=True)
print(df_nan)
#      0
# A  aaa
# B  NaN
# C  NaN

str.extractall(): すべてのマッチ部分を抽出

正規表現のすべてのマッチ部分を抽出するにはstr.extractall()メソッドを使う。

同じ正規表現パターンをstr.extract()str.extractall()に適用し、それぞれの結果を示す。

df_single = s_org.str.extract('(\w+)', expand=True)
print(df_single)
#      0
# A  aaa
# B  bbb
# C  ccc

df_all = s_org.str.extractall('(\w+)')
print(df_all)
#            0
#   match     
# A 0      aaa
#   1      xxx
#   2      com
# B 0      bbb
#   1      yyy
#   2      net
# C 0      ccc
#   1      zzz
#   2       co
#   3       jp

str.extractall()には引数expandは無く、常にindexがマルチインデックスのpandas.DataFrameを返す。

print(df_all.index)
# MultiIndex(levels=[['A', 'B', 'C'], [0, 1, 2, 3]],
#            labels=[[0, 0, 0, 1, 1, 1, 2, 2, 2, 2], [0, 1, 2, 0, 1, 2, 0, 1, 2, 3]],
#            names=[None, 'match'])

マルチインデックスのpandas.DataFrameの要素の指定・選択については以下の記事を参照。

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事