医療職からデータサイエンティストへ

統計学、機械学習に関する記事をまとめています。

Pythonで前処理〜Pandasによる文字列処理まとめ〜

文字列処理

Pandasで前処理を行う際に、文字列の処理に戸惑うことがよくあります。今回は、よく使いそうな文字列処理の方法をまとめていきます。ちなみに前処理全般については過去にまとめましたので、よろしければご覧ください。

また、Rユーザーの方はこちらを

www.medi-08-data-06.work

データの作成

まずは今回文字列処理を行うためのデータセットを作成します。よくありがちな、一つのセルに複数の単語が入っていたり、大文字小文字なども汚いデータを想定します。

import pandas as pd
import numpy as np

register = ['name  TANAKA\nnumber 1', 'name  TANAKA\nnumber 1','name  SATO',
            'name  YAMADA\nnumber 3','name  KATO\nnumber 4']
fruits = ['apple 5', 'orange 4', 'Grape 3', 'Orange 10', np.nan]

df = pd.DataFrame({'register':register, 'fruits':fruits})
df.head()
    register    fruits
0  name TANAKA\nnumber 1  apple 5
1  name TANAKA\nnumber 1  orange 4
2  name SATO   Grape 3
3  name YAMADA\nnumber 3  Orange 10
4  name KATO\nnumber 4    NaN

文字数カウント、大文字小文字変換

Pnadasで文字列処理を行うためには、strアクセサを使います。使い方はSeries.str.hogehogeです。基本的にはPandasのSeries形に対して処理を行います。とりあえず、文字列の長さ計算や、特定文字の個数カウント、大文字小文字変換など基本的な操作をやってみましょう。

  • str.len() : 文字数の数を数える。
  • str.count() : 指定の文字数をカウント
  • str.lower():小文字に変換
  • str.upper():大文字に変換
  • str.title():1文字目を大文字に変換
  • str.swapcase():大文字小文字の入れ替え
#文字数カウント
print(df['register'].str.len())
>0    21
1    21
2    10
3    21
4    19
Name: register, dtype: int64

#特定の文字をカウント
print(df['register'].str.count('T'))
>0    1
1    1
2    1
3    0
4    1
Name: register, dtype: int64

#小文字
print(df['fruits'].str.lower())
>0     apple 5
1    orange 4
2     grape 3
3    orange 8
4         NaN
Name: fruits, dtype: object

#大文字
print(df['fruits'].str.upper())
>0     APPLE 5
1    ORANGE 4
2     GRAPE 3
3    ORANGE 8
4         NaN
Name: fruits, dtype: object

#最初の文字を大文字
print(df['fruits'].str.title())
>0     Apple 5
1    Orange 4
2     Grape 3
3    Orange 8
4         NaN
Name: fruits, dtype: object

#大文字小文字入れ替え
print(df['fruits'].str.swapcase())

>0     APPLE 5
1    ORANGE 4
2     gRAPE 3
3    oRANGE 8
4         NaN
Name: fruits, dtype: object

文字列の結合・分解、

次に指定の文字列を結合・分解して新たな列として追加してみます。この辺りはデータの前処理ではよく使います。文字列の分解では、expandを指定すると、結果をSeries型とDataFrame型で指定できます。

  • str.cat() : 文字列を結合
  • str.split() : 文字列を分解
#register列とfruits列を結合
#sepは結合させる文字
#na_repを指定すると欠損値も扱える。
df['register'].str.cat(df['fruits'],sep=' is ',na_rep='欠損です。')

>0      name  TANAKA\nnumber 1 is apple 5
1     name  TANAKA\nnumber 1 is orange 4
2                  name  SATO is Grape 3
3    name  YAMADA\nnumber 3 is Orange 10
4          name  KATO\nnumber 4 is 欠損です。
Name: register, dtype: object

#register列を改行\nで分解
#expand=Trueは結果をデータフレーム型で返す。
tmp = df['register'].str.split('\n',expand=True)

#さらに空白で分解してデータフレームとして結合
pd.concat([tmp[0].str.split(expand=True),tmp[1].str.split(expand=True)])
0  1
0  name    TANAKA
1  name    TANAKA
2  name    SATO
3  name    YAMADA
4  name    KATO
0  number  1
1  number  1
2  None None
3  number  3
4  number  4

文字列の抽出

次に指定の文字列を含むかどうかの判断させたり、抽出したりしてみます。str.containsstr.extractでは正規表現が使えます。

www.medi-08-data-06.work

  • str.contains(), str.startstiwh(), str.endsstiwh() : 指定の文字列を含むかどうか
  • str.extract() : 指定の文字列を抽出
#TAもしくはYAを含む
print(df["register"].str.contains(r'(TA|YA)', regex=True))
>0     True
1     True
2    False
3     True
4    False

#naで始まる
print(df["register"].str.startswith('na'))
>Name: register, dtype: bool
0    True
1    True
2    True
3    True
4    True
Name: register, dtype: bool

#3でおわる
print(df["register"].str.endswith('3'))
>0    False
1    False
2    False
3     True
4    False
Name: register, dtype: bool

#抜き出し系
#数字の抜き出し
df['fruits'].str.extract(r'(\d+)',expand=True)
    0
0  5
1  4
2  3
3  10
4  NaN

#文字列と数字を別々に抜き出し
df['fruits'].str.extract(r'(\D+)(\d+)',expand=True)
0  1
0  apple   5
1  orange  4
2  Grape   3
3  Orange  10
4  NaN NaN

#列名を指定して抜き出し
#(?P<列名>hogehoge)とする。

df['fruits'].str.extract(r'(?P<fruits>\D+)(?P<number>\d+)',expand=True)
    fruits  num
0  apple   5
1  orange  4
2  Grape   3
3  Orange  10
4  NaN NaN

文字の加工

最後に文字を置換したり、長さをそろえたりしてみます。

  • str.pad():文字の長さを揃える。
  • str.replace:文字の置換
>数字を抜き出し、3文字になるように左側を0で埋める。
df['fruits'].str.extract(r'(\d+)',expand=False).str.pad(width=3, side='left', fillchar='0')
>0    005
1    004
2    003
3    010
4    NaN
Name: fruits, dtype: object

#orangeをBananaに置換
#orangeは正規表現で

df['fruits'].str.replace(r'(.range)', 'Banana')
>0     apple 5
1    Banana 4
2     Grape 3
3    Banana 8
4         NaN
Name: fruits, dtype: object

まとめ

Pythonではstrアクセサを使うと簡単に文字列処理を行うことができます。特に、自然言語処理などでは役立ちそうですね。

参考

Series — pandas 1.0.5 documentation