import pandas as pd
print(pd.__version__)
# 1.5.3
s_org = pd.Series(['[email protected]', '[email protected]', 'ccc'], index=['A', 'B', 'C'])
print(s_org)
# A [email protected]
# B [email protected]
# C ccc
# dtype: object
print(type(s_org))
# <class 'pandas.core.series.Series'>
第一引数patに区切り文字を指定する。分割された文字列のリストを要素とするpandas.Seriesが返される。引数patを省略すると空白で分割される。
s = s_org.str.split('@')
print(s)
# A [aaa, xxx.com]
# B [bbb, yyy.com]
# C [ccc]
# dtype: object
print(type(s))
# <class 'pandas.core.series.Series'>
pandas1.4.0より前のバージョンでは引数patは常に通常の文字列として扱われていたが、1.4.0で引数regexが追加され、その設定によって引数patの扱いが変わるようになった。
デフォルト(regex=None)では、文字数が1の場合は通常文字列、それ以外の場合は正規表現パターンとして扱われる。
print(s_org.str.split(r'@.+\.'))
# A [aaa, com]
# B [bbb, com]
# C [ccc]
# dtype: object
引数patにコンパイルした正規表現パターンを指定することも可能。
関連記事: Pythonの正規表現モジュールreの使い方(match, search, subなど)
import re
pat = re.compile(r'@.+\.')
print(s_org.str.split(pat))
# A [aaa, com]
# B [bbb, com]
# C [ccc]
# dtype: object
引数patは、regex=Trueで常に正規表現パターンとして、Falseで常に通常の文字列として扱われる。1文字の正規表現パターンや2文字以上の通常文字列を指定したい場合は、TrueまたはFalseを指定すればよい。regex=Falseとした場合、patにコンパイルした正規表現パターンを指定するとエラーになるので注意。
複数の列に分割: 引数expand
複数の列に分割してpandas.DataFrameとして取得するには、引数expand=Trueを指定する。デフォルトはexpand=False。
分割数が少ない行の足りない分の要素はNoneとなる。
df = s_org.str.split('@', expand=True)
print(df)
# 0 1
# A aaa xxx.com
# B bbb yyy.com
# C ccc None
print(type(df))
# <class 'pandas.core.frame.DataFrame'>
取得したpandas.DataFrameの列名は0始まりの連番。columns属性などで変更できる。
関連記事: pandas.DataFrameの行名・列名の変更
df.columns = ['local', 'domain']
print(df)
# local domain
# A aaa xxx.com
# B bbb yyy.com
# C ccc None
複数の列に分割せずリストのまま処理したほうが便利なことも多い。以下の記事を参照。
関連記事: pandasの要素としてリストを格納し処理
最大分割回数を指定: 引数n
引数nで最大分割回数を指定できる。デフォルトはn=-1で、すべての区切り文字・正規表現パターンで分割される。
s_org = pd.Series(['a-b-c-d', 'x-y-z', '1'], index=['A', 'B', 'C'])
print(s_org)
# A a-b-c-d
# B x-y-z
# C 1
# dtype: object
print(s_org.str.split('-'))
# A [a, b, c, d]
# B [x, y, z]
# C [1]
# dtype: object
print(s_org.str.split('-', n=1))
# A [a, b-c-d]
# B [x, y-z]
# C [1]
# dtype: object
正規表現にマッチした部分を抽出して分割するには文字列メソッドstr.extract()を使う。
pandas.Series.str.extract — pandas 1.5.3 documentation
以下のpandas.Seriesを例とする。
s_org = pd.Series(['[email protected]', '[email protected]', 'ccc'], index=['A', 'B', 'C'])
print(s_org)
# A [email protected]
# B [email protected]
# C ccc
# dtype: object
第一引数patに正規表現パターンを指定する。正規表現の()で囲まれたグループ部分にマッチする文字列ごとに分割される。複数のグループが抽出される場合はpandas.DataFrameが返される。マッチしない場合はNaN。
df = s_org.str.extract(r'(.+)@(.+)\.(.+)')
print(df)
# 0 1 2
# A aaa xxx com
# B bbb yyy com
# C NaN NaN NaN
グループが一つの場合は引数expand=Trueだとpandas.DataFrame、expand=Falseだとpandas.Seriesを返す。デフォルトはexpand=True。
df = s_org.str.extract(r'(\w+)', expand=True)
print(df)
# 0
# A aaa
# B bbb
# C ccc
print(type(df))
# <class 'pandas.core.frame.DataFrame'>
s = s_org.str.extract(r'(\w+)', expand=False)
print(s)
# A aaa
# B bbb
# C ccc
# dtype: object
print(type(s))
# <class 'pandas.core.series.Series'>
正規表現パターンに名前付きグループ(?P<name>...)を使うと名前がそのまま列名(カラム名)になる。
df_name = s_org.str.extract(
r'(?P<local>.*)@(?P<second_LD>.*)\.(?P<TLD>.*)', expand=True
print(df_name)
# local second_LD TLD
# A aaa xxx com
# B bbb yyy com
# C NaN NaN NaN
引数flagsに正規表現のフラグ(re.IGNORECASEなど)を指定できる。詳細は以下の記事を参照。
関連記事: Pythonの正規表現モジュールreの使い方(match, search, subなど)
なお、マッチ部分が複数ある場合、str.extract()では最初のマッチ部分のみ抽出される。すべてのマッチ部分を抽出するにはstr.extractall()メソッドを使う。以下の記事を参照。
関連記事: pandasの文字列から正規表現で抽出して新たな列を生成
pandas.DataFrameの場合
pandas.DataFrameの特定の列を複数の列に分割して更新する例を紹介する。もっといいやり方があるかもしれない。
以下、str.split()を例として用いるが、str.extract()でも考え方は同じ。
先に作成したpandas.DataFrameを例とする。
print(df)
# local domain
# A aaa xxx.com
# B bbb yyy.com
# C ccc None
特定の列にstr.split()を使うと、分割されたpandas.DataFrameが得られる。
print(df['domain'].str.split('.', expand=True))
# 0 1
# A xxx com
# B yyy com
# C None None
これをpd.concat()を使って元のpandas.DataFrameと連結(結合)し、元の列をdrop()メソッドで削除する。
関連記事: pandas.DataFrame, Seriesを連結するconcat
関連記事: pandas.DataFrameの行・列を指定して削除するdrop
df2 = pd.concat([df, df['domain'].str.split('.', expand=True)], axis=1).drop(
'domain', axis=1
print(df2)
# local 0 1
# A aaa xxx com
# B bbb yyy com
# C ccc None None
連結(結合)するときに元のpandas.DataFrameから必要な列だけ選択してもいい。
df3 = pd.concat([df['local'], df['domain'].str.split('.', expand=True)], axis=1)
print(df3)
# local 0 1
# A aaa xxx com
# B bbb yyy com
# C ccc None None
特定の列名を変更するにはrename()メソッドを使う。
df3.rename(columns={0: 'second_LD', 1: 'TLD'}, inplace=True)
print(df3)
# local second_LD TLD
# A aaa xxx com
# B bbb yyy com
# C ccc None None
関連記事: pandas.DataFrameの行名・列名の変更
pandasで特定の文字列を含む行を抽出(完全一致、部分一致)
pandasでstack, unstack, pivotを使ってデータを整形
pandasで要素・行・列に関数を適用するmap, apply, applymap
pandasで時系列データの曜日や月、四半期、年ごとの合計や平均を算出
pandasのcut, qcut関数でビニング処理(ビン分割)
pandas.DataFrame, SeriesとNumPy配列ndarrayを相互に変換
pandasで文字列と数値を相互変換、書式変更
pandasの文字列から正規表現で抽出して新たな列を生成
pandasで四捨五入・偶数丸め・切り捨て・切り上げ
Pythonで正規化・標準化(リスト、NumPy配列、pandas.DataFrame)
pandasで条件に応じて値を置換(where, mask)
pandas.Seriesのmapメソッドで列の要素を置換
pandasのバージョンを確認(pd.show_versions)
pandas.DataFrame, Seriesの重複した行を抽出・削除
pandasで中央値を取得するmedian