Pandasでできる文字列操作として、スライス表記と正規表現を使った文字列抽出を行うことがあります。

スライス表記はPython本来のものと同じ感覚で扱うことが可能です。

文字列のスライス表記

スライス表記は左から何文字目から何文字目までを取ってくるかを選択することができる表記方法で、文字列以外にもリストやタプル、NumPyのndarrayなどに広く使われている記法です。

Pythonでは

[始点:終点]

という形式で指定しますが、始点は範囲に含まれ、終点は範囲に含まれません

.str[2:5]のような形式で使われます。

順番を指定して1文字だけ取り出す

まずは1文字だけ取り出します。

一番左側の文字列は0番目 です。

In [1]: import pandas as pd

In [2]: sr = pd.Series(['a123a21','b242b33','c122c222'])

In [3]: sr
Out[3]:
0     a123a21
1     b242b33
2    c122c222
dtype: object

In [4]: sr.str[0] # 先頭の文字を切り出す
Out[4]:
0    a
1    b
2    c
dtype: object

In [5]: sr.str[3] # 0,1,2,3番目の文字
Out[5]:
0    3
1    2
2    2
dtype: object

In [6]: sr.str[-1] # -1だと最後の文字
Out[6]:
0    1
1    3
2    2
dtype: object

スライス表記

スライス表記を使って文字列の塊を抜き出します。

文字列を最初から含む場合、もしくは最後まで含む場合はスライス表記の始点、終点指定を省略することが可能です。

In [7]: sr.str[1:4] # 1,2,3番目
Out[7]:
0    123
1    242
2    122
dtype: object

In [8]: sr.str[:4] # 最初から3番目まで
Out[8]:
0    a123
1    b242
2    c122
dtype: object

In [9]: sr.str[4:] # 4番目から最後まで
Out[9]:
0     a21
1     b33
2    c222
dtype: object

複数文字ごとに取り出す

スライス表記を使って1つ飛ばしや2つ飛ばしに文字を取り出すことが可能です。

[始点:終点:間隔]のように指定できます。

間隔の部分を-1に指定すると逆順になります。

In [11]: sr.str[::2] # 1つ飛ばし
Out[11]:
0    a2a1
1    b4b3
2    c2c2
dtype: object

In [12]: sr.str[::-1] # 逆順
Out[12]:
0     12a321a
1     33b242b
2    222c221c
dtype: object

In [13]: sr.str[::3] # 2つ飛ばし
Out[13]:
0    a31
1    b23
2    c22
dtype: object

文字列の抽出

Series.str.extract関数を使って文字列の抽出を行います。 この関数はパターンにマッチする最初の文字列 を抜き出す関数となっています。

s

特定の文字列の抽出

まずは、特定の文字列を抽出してみましょう。

In [18]: sr
Out[18]:
0     a123a21
1     b242b33
2    c122c222
dtype: object

In [21]: sr.str.extract('(a)(1)') # aと1があったら抽出
Out[21]:
     0    1
0    a    1
1  NaN  NaN
2  NaN  NaN

( )で囲んだものが1つのカラムとして分割されます。

見つからなかった場合はNaN値となります。

正規表現を使った文字列の抽出

Series.str.extract関数はデフォルトで正規表現が使えるようになっているのでこちらを使って(アルファベット)(数字3桁)を抜き出してみましょう。

パターンにマッチする最初のものしか抜き出されないので、'c122c222'の部分だと'c122'だけが抜き出される結果となります。

In [22]: sr.str.extract('([a-z])([0-9]{3})')
Out[22]:
   0    1
0  a  123
1  b  242
2  c  122

3つに分割することも可能です。

In [24]: sr.str.extract('([a-z])([0-9]{3})([ab])', expand=True)
Out[24]:
     0    1    2
0    a  123    a
1    b  242    b
2  NaN  NaN  NaN

カラムラベルを設定する

それぞれの条件指定の所の先頭に?P<ラベル名>を付け加えると、分割後の列データのラベルが指定されます。

In [25]: sr.str.extract('(?P<class>[a-z])(?P<number>[0-9]{3})') # class ,numberというラベルを設定
Out[25]:
  class number
0     a    123
1     b    242
2     c    122

パターンに合致した全ての文字列を取り出す

Series.str.extract関数ですと、パターンに合致する最初の文字列 のみを抜き出しますが、 Series.str.extractall関数ならば、全て抜き出すことが可能です。

使い方はextract関数とほとんど変わりません。 この場合、結果はMultiIndexで返されます。

In [26]: sr.str.extractall('([a-z])([0-9]{2})')
Out[26]:
         0   1
  match       
0 0      a  12
  1      a  21
1 0      b  24
  1      b  33
2 0      c  12
  1      c  22

まとめ

今回は文字列のスライス表記とextract関数を使った文字列の抽出方法について扱いました。

スライス表記はリストなどで扱ったことのある人にとっては使い方が全く一緒だったのですぐに理解できたと思います。

extract関数を使った抽出では、正規表現を使うことがほとんどになると思うので、正規表現も合わせて把握できるようにしておくと、Pandasでの文字列抽出が非常に楽にできるようになるでしょう。

参考