LoginSignup
3
2

More than 1 year has passed since last update.

Pandasユーザーガイド「テキストデータの操作」(公式ドキュメント日本語訳)

Last updated at Posted at 2020-07-21

本記事は、Pandas の公式ドキュメントのUser Guide - Working with text dataを機械翻訳した後、一部の不自然な文章を手直ししたものである。

誤訳の指摘・代訳案・質問等があればコメント欄や編集リクエストでお願いします。

テキストデータの操作

テキストデータの型

バージョン1.0.0で追加

pandasではテキストデータを保持する方法が2つあります。

  • objectデータ型の NumPy 配列。
  • StringDtype拡張型。

StringDtypeを使用してテキストデータを保持することをお勧めします。

pandas 1.0 以前は、objectデータ型が唯一の方法でした。これは多くの理由で不便でした。

  1. 誤って文字列と非文字列を混在させてobjectデータ型配列に格納する可能性があります。専用のデータ型があるのが良いでしょう。
  2. objectデータ型は、DataFrame.select_dtypes()のようなデータ型固有の操作に適用できません。依然としてobjectデータ型の列である非テキスト列を除外しながら、テキストのみの列を選択する有効的な方法はありません。
  3. コードを読むとき、obejctデータ型配列の内容は'string'よりも明示的ではありません。

現在、文字列を格納したobjectデータ型配列とarray.StringArrayのパフォーマンスはほぼ変わり有りません。今後の機能強化により、StringArrayのパフォーマンスが大幅に向上し、メモリオーバーヘッドが低下することが予想されます。

StringArrayは現在、実験的と見なされています。実装と部分的なAPIは、警告なしに変更される場合があります。

後方互換性のために、文字列のリストから推測する際のデフォルトの型は依然としてobjectデータ型です。

pd.Series(["a", "b", "c"])
# 0    a
# 1    b
# 2    c
# dtype: object

stringデータ型を明示的に要求するには、dtypeを指定します。

pd.Series(["a", "b", "c"], dtype="string")
# 0    a
# 1    b
# 2    c
# dtype: string

pd.Series(["a", "b", "c"], dtype=pd.StringDtype())
# 0    a
# 1    b
# 2    c
# dtype: string

または、既に存在するSeriesまたはDataFrameastypeを適用して、

s = pd.Series(["a", "b", "c"])

s
# 0    a
# 1    b
# 2    c
# dtype: object

s.astype("string")
# 0    a
# 1    b
# 2    c
# dtype: string

バージョン 1.1.0 で変更

非文字列データを文字列データ型に変換するのにStringDtype"string"を使用することもできます。

s = pd.Series(["a", 2, np.nan], dtype="string")

s
# 0       a
# 1       2
# 2    <NA>
# dtype: string

type(s[1])
# str

または、既に存在するpandasのデータを変換して、

s1 = pd.Series([1, 2, np.nan], dtype="Int64")

s1
# 0       1
# 1       2
# 2    <NA>
# dtype: Int64

s2 = s1.astype("string")

s2
# 0       1
# 1       2
# 2    <NA>
# dtype: string

type(s2[0])
# str

動作の違い

以下に、StringDtypeオブジェクトの動作がobjectデータ型と異なる点を紹介します。

  1. StringDtypeの場合、数値の出力を返す文字列アクセサメソッドは、欠損値の存在に応じて、整数または浮動小数データ型ではなく、常に欠損値許容整数データ型(Int64データ型)を返します。真偽値の出力を返すメソッドは、欠損値許容真偽値データ型(booleanデータ型)を返します。

    s = pd.Series(["a", None, "b"], dtype="string")
    
    s
    # 0       a
    # 1    <NA>
    # 2       b
    # dtype: string
    
    s.str.count("a")
    # 0       1
    # 1    <NA>
    # 2       0
    # dtype: Int64
    
    s.dropna().str.count("a")
    # 0    1
    # 2    0
    # dtype: Int64
    

    両方とも出力はInt64データ型です。オブジェクトデータ型と比較してください。

    s2 = pd.Series(["a", None, "b"], dtype="object")
    
    s2.str.count("a")
    # 0    1.0
    # 1    NaN
    # 2    0.0
    # dtype: float64
    
    s2.dropna().str.count("a")
    # 0    1
    # 2    0
    # dtype: int64
    

    オブジェクトデータ型では、欠損値が存在する場合、出力データ型はfloat64になります。真偽値を返すメソッドの場合も同様です。

    s.str.isdigit()
    # 0    False
    # 1     <NA>
    # 2    False
    # dtype: boolean
    
    s.str.match("a")
    # 0     True
    # 1     <NA>
    # 2    False
    # dtype: boolean
    
  2. StringArrayはバイトではなく文字列のみを保持するため、Series.str.decode()などの一部の文字列メソッドはStringArrayでは使用できません。

  3. 比較操作では、array.StringArrayおよびStringArrayを基にしたSeriesは、boolデータ型オブジェクトではなくBooleanDtypeのオブジェクトを返します。StringArrayの欠損値は、numpy.nanのように常に等しくないという結果を返すのではなく、比較演算を行っても伝播します。

このドキュメントの以下で紹介する、その他の関数・メソッド等は、stringobjectデータ型に等しく適用されます。

文字列メソッド

Series および Index には、配列の各要素を簡単に操作できる一連の文字列処理メソッドが実装されています。これらのメソッドが欠損値・ NA 値を自動的に除外することは、重要なことかもしれません。これらはstr属性を介してアクセスされ、多くの場合、同等の(スカラー)組み込み文字列メソッドに一致する名前を持ちます。

s = pd.Series(
    ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
)


s.str.lower()
# 0       a
# 1       b
# 2       c
# 3    aaba
# 4    baca
# 5    <NA>
# 6    caba
# 7     dog
# 8     cat
# dtype: string

s.str.upper()
# 0       A
# 1       B
# 2       C
# 3    AABA
# 4    BACA
# 5    <NA>
# 6    CABA
# 7     DOG
# 8     CAT
# dtype: string

s.str.len()
# 0       1
# 1       1
# 2       1
# 3       4
# 4       4
# 5    <NA>
# 6       4
# 7       3
# 8       3
# dtype: Int64
idx = pd.Index([" jack", "jill ", " jesse ", "frank"])

idx.str.strip()
# Index(['jack', 'jill', 'jesse', 'frank'], dtype='object')

idx.str.lstrip()
# Index(['jack', 'jill ', 'jesse ', 'frank'], dtype='object')

idx.str.rstrip()
# Index([' jack', 'jill', ' jesse', 'frank'], dtype='object')

Indexにおける文字列メソッドは、データフレームの列のクリーンアップまたは変換に特に役立ちます。たとえば、先頭または末尾に空白がある列がある場合を考えます。

df = pd.DataFrame(
    np.random.randn(3, 2), columns=[" Column A ", " Column B "], index=range(3)
)


df
#     Column A    Column B
# 0    0.469112   -0.282863
# 1   -1.509059   -1.135632
# 2    1.212112   -0.173215

df.columnsはインデックスオブジェクトなので、.strアクセサを使用できます。

df.columns.str.strip()
# Index(['Column A', 'Column B'], dtype='object')

df.columns.str.lower()
# Index([' column a ', ' column b '], dtype='object')

これらの文字列メソッドを使用して、必要に応じて列をクリーンアップできます。次の例は、先頭と末尾の空白を削除し、すべての名前を小文字にし、残りの空白をアンダースコアに置き換えています。

df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_")

df
#    column_a  column_b
# 0  0.469112 -0.282863
# 1 -1.509059 -1.135632
# 2  1.212112 -0.173215

多数の要素が繰り返されるSeriesがある場合(つまり、Series内の一意の要素の数がSeriesの長さよりもはるかに小さい場合)、元のSeriescategory型に変換したものを作成し、それに対して.str.<method>.dt.<property>を適用する方が高速です。このパフォーマンスの違いは、category型のSeriesの場合、文字列操作はSeriesの各要素ではなく.categoriesで実行されることによります。

文字列の.categoriesを持つcategory型のSeriesには、文字列型のSeriesと比較していくつかの制限があることに注意してください(例えばs + " " + sは、scategory型のSeriesの場合機能しません。)。また、list型の要素を操作する.strメソッドも、そのようなSeriesでは使用できません。

バージョン0.25.0以前は、.strアクセサは最も初歩的な型チェックのみを行いました。バージョン0.25.0以降、より厳密に、シリーズの型が推測され、許容される型(つまり文字列)が適用されます。

一般的に、.strアクセサは文字列でのみ機能するように設計されています。非常に少数の例外を除いて、他の用途はサポートされておらず、後で無効になる可能性があります。

文字列の分割と置換

splitなどのメソッドは、リストからなるSeriesを返します。

s2 = pd.Series(["a_b_c", "c_d_e", np.nan, "f_g_h"], dtype="string")

s2.str.split("_")
# 0    [a, b, c]
# 1    [c, d, e]
# 2         <NA>
# 3    [f, g, h]
# dtype: object

分割したリストの要素には、getまたは[]表記を使用してアクセスできます。

s2.str.split("_").str.get(1)
# 0       b
# 1       d
# 2    <NA>
# 3       g
# dtype: object

s2.str.split("_").str[1]
# 0       b
# 1       d
# 2    <NA>
# 3       g
# dtype: object

expand引数によって簡単に、これを展開してDataFrameとして返すことができます。

s2.str.split("_", expand=True)
#       0     1     2
# 0     a     b     c
# 1     c     d     e
# 2  <NA>  <NA>  <NA>
# 3     f     g     h

元のSeriesStringDtypeがある場合、出力列もすべてStringDtypeになります。

分割数を制限することもできます。

s2.str.split("_", expand=True, n=1)
#       0     1
# 0     a   b_c
# 1     c   d_e
# 2  <NA>  <NA>
# 3     f   g_h

rsplitsplitと似ていますが、逆方向、つまり文字列の末尾から文字列の先頭に向かって動作する点が異なります。

s2.str.rsplit("_", expand=True, n=1)
#       0     1
# 0   a_b     c
# 1   c_d     e
# 2  <NA>  <NA>
# 3   f_g     h

replaceはオプションで正規表現を使用します。
(訳注:Series.str.replace()regexオプションのデフォルトは現在Trueになっているが、将来Falseに変更される予定)

s3 = pd.Series(
    ["A", "B", "C", "Aaba", "Baca", "", np.nan, "CABA", "dog", "cat"],
    dtype="string",
)


s3
# 0       A
# 1       B
# 2       C
# 3    Aaba
# 4    Baca
# 5
# 6    <NA>
# 7    CABA
# 8     dog
# 9     cat
# dtype: string

s3.str.replace("^.a|dog", "XX-XX ", case=False, regex=True)
# 0           A
# 1           B
# 2           C
# 3    XX-XX ba
# 4    XX-XX ca
# 5
# 6        <NA>
# 7    XX-XX BA
# 8      XX-XX
# 9     XX-XX t
# dtype: string

正規表現を扱う際には、いくつかの注意が必要です。現在の動作では、regexTrueに設定されている場合でも、1文字のパターンをリテラル文字列として扱います。この動作は非推奨で、将来のバージョンでは削除され、regexキーワードが常に尊重されるようになる予定です。

バージョン1.2.0で変更

str.replace()と同様の)文字列のリテラル置換を行いたい場合は、各文字をエスケープするのではなく、オプションのregexパラメータをFalseに設定します。この場合、patreplは両方とも文字列でなければなりません。

dollars = pd.Series(["12", "-$10", "$10,000"], dtype="string")

# 次の2つは同等
dollars.str.replace(r"-\$", "-", regex=True)
# 0         12
# 1        -10
# 2    $10,000
# dtype: string

dollars.str.replace("-$", "-", regex=False)
# 0         12
# 1        -10
# 2    $10,000
# dtype: string

replaceメソッドは、関数を呼び出して置換することもできます。re.sub()を使用して、すべてのpatに対して呼び出されます。呼び出し可能オブジェクトは、1つの位置引数(正規表現オブジェクト)を受け取り、文字列を返す必要があります。

# 小文字のアルファベットの綴りをすべて反転させる
pat = r"[a-z]+"

def repl(m):
    return m.group(0)[::-1]


pd.Series(["foo 123", "bar baz", np.nan], dtype="string").str.replace(
    pat, repl, regex=True
)

# 0    oof 123
# 1    rab zab
# 2       <NA>
# dtype: string

# 正規表現グループを使用
pat = r"(?P<one>\w+) (?P<two>\w+) (?P<three>\w+)"

def repl(m):
    return m.group("two").swapcase()


pd.Series(["Foo Bar Baz", np.nan], dtype="string").str.replace(
    pat, repl, regex=True
)

# 0     bAR
# 1    <NA>
# dtype: string

replaceメソッドは、パターンとしてre.compile()からコンパイルされた正規表現オブジェクトも受け入れます。すべてのフラグは、コンパイル済みの正規表現オブジェクトに含める必要があります。

import re

regex_pat = re.compile(r"^.a|dog", flags=re.IGNORECASE)

s3.str.replace(regex_pat, "XX-XX ", regex=True)
# 0           A
# 1           B
# 2           C
# 3    XX-XX ba
# 4    XX-XX ca
# 5
# 6        <NA>
# 7    XX-XX BA
# 8      XX-XX
# 9     XX-XX t
# dtype: string

コンパイルされた正規表現オブジェクトでreplaceを呼び出すときにflags引数を使うと、ValueErrorが発生します。

s3.str.replace(regex_pat, 'XX-XX ', flags=re.IGNORECASE)
# ---------------------------------------------------------------------------
# ValueError: case and flags cannot be set when pat is a compiled regex

removeprefixremovesuffixは、Python 3.9で追加されたstr.removeprefixstr.removesuffixと同じ効果を持っています。

バージョン1.4.0で追加

s = pd.Series(["str_foo", "str_bar", "no_prefix"])

s.str.removeprefix("str_")
# 0          foo
# 1          bar
# 2    no_prefix
# dtype: object

s = pd.Series(["foo_str", "bar_str", "no_suffix"])

s.str.removesuffix("_str")
# 0          foo
# 1          bar
# 2    no_suffix
# dtype: object

結合

seriesIndexをそれ自体ないし他と結合するには、すべてcat()またはIndex.str.catに基づいたいくつかの方法があります。

単一のSeriesと文字列の結合

Series(またはIndex)の各要素を結合できます。

s = pd.Series(["a", "b", "c", "d"], dtype="string")

s.str.cat(sep=",")
# 'a,b,c,d'

区切り文字を指定する引数sepが指定されていない場合、デフォルトとして空の文字列sep=''になります。

s.str.cat()
# 'abcd'

デフォルトでは、欠損値は無視されます。na_repを使用して、表現を指定できます。

t = pd.Series(["a", "b", np.nan, "d"], dtype="string")

t.str.cat(sep=",")
# 'a,b,d'

t.str.cat(sep=",", na_rep="-")
# 'a,b,-,d'

Seriesにリスト等を結合

cat()の最初の引数には、呼び出し元のSeries(またはIndex)の長さと一致する、リストライクなオブジェクトを渡すことができます。

s.str.cat(["A", "B", "C", "D"])
# 0    aA
# 1    bB
# 2    cC
# 3    dD
# dtype: string

na_repが指定されていない場合、どちらか一方にでも欠損値があれば、結果も欠損値になります。

s.str.cat(t)
# 0      aa
# 1      bb
# 2    <NA>
# 3      dd
# dtype: string

s.str.cat(t, na_rep="-")
# 0    aa
# 1    bb
# 2    c-
# 3    dd
# dtype: string

Seriesに配列等を結合

othersパラメーターには2次元のデータを渡すこともできます。この場合、行数は呼び出し元のSeries(またはIndex)の長さと一致する必要があります。

d = pd.concat([t, s], axis=1)

s
# 0    a
# 1    b
# 2    c
# 3    d
# dtype: string

d
#       0  1
# 0     a  a
# 1     b  b
# 2  <NA>  c
# 3     d  d

s.str.cat(d, na_rep="-")
# 0    aaa
# 1    bbb
# 2    c-c
# 3    ddd
# dtype: string

Series にインデックスに基づいてオブジェクトを結合

SeriesまたはDataFrameとの結合の場合、joinキーワードを設定することにより、結合する前にインデックスを調整できます。

u = pd.Series(["b", "d", "a", "c"], index=[1, 3, 0, 2], dtype="string")

s
# 0    a
# 1    b
# 2    c
# 3    d
# dtype: string

u
# 1    b
# 3    d
# 0    a
# 2    c
# dtype: string

s.str.cat(u)
# 0    aa
# 1    bb
# 2    cc
# 3    dd
# dtype: string

s.str.cat(u, join="left")
# 0    aa
# 1    bb
# 2    cc
# 3    dd
# dtype: string

joinキーワードが渡されなかった場合、cat()メソッドは現在、バージョン0.23.0より前の動作(つまり、整列なし)にフォールバックしますが、将来のバージョンではこのデフォルトがjoin='left'に変更されるため、関連するインデックスのいずれかが異なる場合はFutureWarningが発生します。

joinには通常のオプションを使用できます('left', 'outer', 'inner', 'right'のいずれか)。ここで行われるアラインメントは、長さを一致させる必要がないことも意味します。

v = pd.Series(["z", "a", "b", "d", "e"], index=[-1, 0, 1, 3, 4], dtype="string")

s
# 0    a
# 1    b
# 2    c
# 3    d
# dtype: string

v
# -1    z
#  0    a
#  1    b
#  3    d
#  4    e
# dtype: string

s.str.cat(v, join="left", na_rep="-")
# 0    aa
# 1    bb
# 2    c-
# 3    dd
# dtype: string

s.str.cat(v, join="outer", na_rep="-")
# -1    -z
#  0    aa
#  1    bb
#  2    c-
#  3    dd
#  4    -e
# dtype: string

同様に、othersDataFrameであっても実行可能です。

f = d.loc[[3, 2, 1, 0], :]

s
# 0    a
# 1    b
# 2    c
# 3    d
# dtype: string

f
#       0  1
# 3     d  d
# 2  <NA>  c
# 1     b  b
# 0     a  a

s.str.cat(f, join="left", na_rep="-")
# 0    aaa
# 1    bbb
# 2    c-c
# 3    ddd
# dtype: string

Series と複数のオブジェクトの結合

複数の配列ライクのオブジェクト(具体的には、SeriesIndex・および1次元のnp.ndarrayバリアント)は、リストライクなコンテナ(イテレータやdict-views などを含む)を用いて結合することができます。

s
# 0    a
# 1    b
# 2    c
# 3    d
# dtype: string

u
# 1    b
# 3    d
# 0    a
# 2    c
# dtype: string

s.str.cat([u, u.to_numpy()], join="left")
# 0    aab
# 1    bbd
# 2    cca
# 3    ddc
# dtype: string

渡されたリストのうち、インデックスのない要素(例:np.ndarray)は呼び出し元のSeries(またはIndex)と長さが一致している必要がありますが、SeriesIndexは(join=Noneで整列が無効にされていない限り)長さは自由です。

v
# -1    z
#  0    a
#  1    b
#  3    d
#  4    e
# dtype: string

s.str.cat([v, u, u.to_numpy()], join="outer", na_rep="-")
# -1    -z--
#  0    aaab
#  1    bbbd
#  2    c-ca
#  3    dddc
#  4    -e--
# dtype: string

othersに渡したリストが異なるインデックスを含む状態でjoin='right'を指定した場合、返されるオブジェクトはこれらのインデックスの和(union)に基づいて形成されます。

u.loc[[3]]
# 3    d
# dtype: string

v.loc[[-1, 0]]
# -1    z
#  0    a
# dtype: string

s.str.cat([u.loc[[3]], v.loc[[-1, 0]]], join="right", na_rep="-")
#  3    dd-
# -1    --z
#  0    a-a
# dtype: string

.strを用いた索引

[]記法を使用して、位置の場所を指定することで直接索引できます。文字列の末尾を超えて索引すると、結果はNaNになります。

s = pd.Series(
    ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
)


s.str[0]
# 0       A
# 1       B
# 2       C
# 3       A
# 4       B
# 5    <NA>
# 6       C
# 7       d
# 8       c
# dtype: string

s.str[1]
# 0    <NA>
# 1    <NA>
# 2    <NA>
# 3       a
# 4       a
# 5    <NA>
# 6       A
# 7       o
# 8       a
# dtype: string

部分文字列の抽出

各要素の最初の一致を抽出(extract)

バージョン0.23以前は、extractメソッドのexpand引数のデフォルトはFalseに設定されていました。expand=Falseの場合、expandは、対象文字列と正規表現パターンに応じて、SeriesIndexDataFrameのいずれかを返します。expand=Trueの場合は、常にDataFrameを返します。これはユーザーの観点から見ると、より一貫性があり混乱が少ないです。expand=Trueは、バージョン0.23.0以降はデフォルトになりました。

extractメソッドは、少なくとも1つのキャプチャグループを持つ正規表現を受け取ります。

複数のグループを持つ正規表現を抽出すると、グループごとに1つの列を持つデータフレームが返されます。

pd.Series(
    ["a1", "b2", "c3"],
    dtype="string",
).str.extract(r"([ab])(\d)", expand=False)
#       0     1
# 0     a     1
# 1     b     2
# 2  <NA>  <NA>

一致しない要素は、NaNで満たされた行を返します。したがって、乱雑な文字列のシリーズは、タプルまたはre.matchオブジェクトにアクセスするのにget()を必要とせずに、クリーンアップされた、またはより有用な文字列の同様のインデックス付きシリーズまたはデータフレームに「変換」できます。一致が見つからず、結果がNaNのみであっても、データ型は常にオブジェクトです(訳注:元がstringの場合はstringになるはず)。

名前付きグループや、

pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(
    r"(?P<letter>[ab])(?P<digit>\d)", expand=False
)
#   letter digit
# 0      a     1
# 1      b     2
# 2   <NA>  <NA>

オプションのグループ

pd.Series(
    ["a1", "b2", "3"],
    dtype="string",
).str.extract(r"([ab])?(\d)", expand=False)
#       0  1
# 0     a  1
# 1     b  2
# 2  <NA>  3

を使用することもできます。正規表現のキャプチャグループ名は、それぞれの列名に使用されることを覚えておいてください。キャプチャグループ名が存在しない場合は、キャプチャグループ番号が使用されます。

グループを1つだけ持つ正規表現によって抽出すると、expand=Trueの場合、1つの列からなるDataFrameが返されます。

pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"[ab](\d)", expand=True)
#       0
# 0     1
# 1     2
# 2  <NA>

expand=Falseの場合は、Seiresが返されます。

pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"[ab](\d)", expand=False)
# 0       1
# 1       2
# 2    <NA>
# dtype: string

Indexに対してキャプチャグループをちょうど1つだけ持つ正規表現で呼び出すと、expand=Trueの場合、1つの列からなるDataFrameが返されます。

s = pd.Series(["a1", "b2", "c3"], ["A11", "B22", "C33"], dtype="string")

s
# A11    a1
# B22    b2
# C33    c3
# dtype: string

s.index.str.extract("(?P<letter>[a-zA-Z])", expand=True)
#   letter
# 0      A
# 1      B
# 2      C

expand=Falseの場合は、Indexが返されます。

s.index.str.extract("(?P<letter>[a-zA-Z])", expand=False)
# Index(['A', 'B', 'C'], dtype='object', name='letter')

Indexに対してキャプチャグループを複数持つ正規表現で呼び出すと、expand=Trueの場合、DataFrameが返されます。

s.index.str.extract("(?P<letter>[a-zA-Z])([0-9]+)", expand=True)
#   letter   1
# 0      A  11
# 1      B  22
# 2      C  33

expand=Falseの場合は、ValueErrorが発生します。

s.index.str.extract("(?P<letter>[a-zA-Z])([0-9]+)", expand=False)
# ValueError: only one regex group is supported with Index

次の表は、extract(expand=False)の動作をまとめたものです(1列目は入力サブジェクト、1行目は正規表現のグループ数)。

1 グループ >1 グループ
Index Index ValueError
Series Series DataFrame

各要素のすべての一致を抽出(extractall)

(最初の一致のみを抽出する)extractとは異なり、

s = pd.Series(["a1a2", "b1", "c1"], index=["A", "B", "C"], dtype="string")

s
# A    a1a2
# B      b1
# C      c1
# dtype: string

two_groups = "(?P<letter>[a-z])(?P<digit>[0-9])"

s.str.extract(two_groups, expand=True)
#   letter digit
# A      a     1
# B      b     1
# C      c     1

extractallメソッドはすべての一致を返します。extractallの結果は常に、MultiIndexを行に持つDataFrameです。MultiIndexの最低レベルはmatchという名前で、要素の順序を示します。

s.str.extractall(two_groups)
#         letter digit
#   match
# A 0          a     1
#   1          a     2
# B 0          b     1
# C 0          c     1

Series の各要素の文字列に1回だけ一致する場合、

s = pd.Series(["a3", "b3", "c2"], dtype="string")

s
# 0    a3
# 1    b3
# 2    c2
# dtype: string

extractall(pat).xs(0, level='match')は、extract(pat)と同じ結果になります。

extract_result = s.str.extract(two_groups, expand=True)

extract_result
#   letter digit
# 0      a     3
# 1      b     3
# 2      c     2

extractall_result = s.str.extractall(two_groups)

extractall_result
#         letter digit
#   match
# 0 0          a     3
# 1 0          b     3
# 2 0          c     2

extractall_result.xs(0, level="match")
#   letter digit
# 0      a     3
# 1      b     3
# 2      c     2

Index.str.extractallをサポートしています。デフォルトの(0から始まる)インデックスを持つSeries.str.extractallと同じ結果の、DataFrameを返します。

pd.Index(["a1a2", "b1", "c1"]).str.extractall(two_groups)
#         letter digit
#   match
# 0 0          a     1
#   1          a     2
# 1 0          b     1
# 2 0          c     1

pd.Series(["a1a2", "b1", "c1"], dtype="string").str.extractall(two_groups)
#         letter digit
#   match
# 0 0          a     1
#   1          a     2
# 1 0          b     1
# 2 0          c     1

パターンに一致する、またはパターンを含む文字列のテスト

要素にパターンが含まれているかどうかを確認できます。

pattern = r"[0-9][a-z]"

pd.Series(
    ["1", "2", "3a", "3b", "03c", "4dx"],
    dtype="string",
).str.contains(pattern)

# 0    False
# 1    False
# 2     True
# 3     True
# 4     True
# 5     True
# dtype: boolean

また、要素がパターンに一致するかどうかも確認できます。

pd.Series(
    ["1", "2", "3a", "3b", "03c", "4dx"],
    dtype="string",
).str.match(pattern)

# 0    False
# 1    False
# 2     True
# 3     True
# 4    False
# 5     True
# dtype: boolean

バージョン1.1.0で追加

pd.Series(
    ["1", "2", "3a", "3b", "03c", "4dx"],
    dtype="string",
).str.fullmatch(pattern)

# 0    False
# 1    False
# 2     True
# 3     True
# 4    False
# 5    False
# dtype: boolean

matchfullmatchcontainsの違いは厳密さです。fullmatchは文字列全体が正規表現にマッチするかどうかをテストし、matchは文字列の先頭を見て正規表現にマッチするかどうかをテストし、containsは文字列内の任意の位置に正規表現にマッチする部分があるかどうかをテストします。

これら3つの一致モードは、reパッケージにおけるre.fullmatchre.matchre.searchにそれぞれ対応します。

matchfullmatchcontainsstartswithendswithなどのメソッドはオプションのna引数を受け取って、欠損値をTrueまたはFalseと見なすことができます。

s4 = pd.Series(
    ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
)


s4.str.contains("A", na=False)
# 0     True
# 1    False
# 2    False
# 3     True
# 4    False
# 5    False
# 6     True
# 7    False
# 8    False
# dtype: boolean

標識変数の作成

文字列の列をダミー変数化できます。たとえば、|で区切られている場合、

s = pd.Series(["a", "a|b", np.nan, "a|c"], dtype="string")

s.str.get_dummies(sep="|")
#    a  b  c
# 0  1  0  0
# 1  1  1  0
# 2  0  0  0
# 3  1  0  1

文字列Indexも、MultiIndexを返すget_dummiesをサポートしています。

idx = pd.Index(["a", "a|b", np.nan, "a|c"])

idx.str.get_dummies(sep="|")
# MultiIndex([(1, 0, 0),
#             (1, 1, 0),
#             (0, 0, 0),
#             (1, 0, 1)],
#            names=['a', 'b', 'c'])

get_dummies()についての説明もご覧ください。

主なメソッド

メソッド 説明
cat() 文字列を連結
split() 区切り文字を指定して文字列を分割
rsplit() 区切り文字を指定して文字列を末尾から分割
get() 各要素へのインデックス(i 番目の要素を取得)
join() 渡された区切り文字でシリーズの各要素の文字列を結合
get_dummies() 区切り文字を指定して文字列を分割し、ダミー変数化した DataFrame を返す
contains() 各文字列にパターン・正規表現が含まれるかどうかの、真偽値配列を返す
replace() パターン・正規表現・文字列に一致する部分を、他の文字列または呼び出し可能オブジェクトの戻り値に置換
removeprefix() 文字列から接頭辞を取り除く、つまり、文字列が接頭辞で始まる場合のみ取り除く
removesuffix() 文字列から接尾辞を取り除く、つまり、文字列が接尾辞で終わる場合のみ取り除く
repeat() 文字列を複製(s.str.repeat(3)x * 3に等しい)
pad() 文字列の左・右または両側に空白を追加
center() str.centerに同じ
ljust() str.ljustに同じ
rjust() str.rjustに同じ
zfill() str.zfillに同じ
wrap() 長い文字列を指定した値以下の長さの行に分割
slice() Series の各文字列をスライス
slice_replace() スライスした Series の各文字列を、指定した値に置換
count() パターンの出現回数をカウント
startswith() 各要素に対してstr.startswith(pat)を適用するのと同じ
endswith() 各要素に対してstr.endswith(pat)を適用するのと同じ
findall() 各文字列に対して、全てのパターン・正規表現の一致リストを返す
match() 各要素に対してre.matchを適用し、パターン・正規表現に一致するかどうかの真偽値配列を返す
extract() 各要素に対してre.searchを適用し、各要素が行、各正規表現キャプチャグループが列の DataFrame を返す
extractall() 各要素に対してre.findallを適用し、各要素が行、各正規表現キャプチャグループが列の DataFrame を返す
len() 文字列の長さ
strip() str.stripに同じ
rstrip() str.rstripに同じ
lstrip() str.lstripに同じ
partition() str.partitionに同じ
rpartition() str.rpartitionに同じ
lower() str.lowerに同じ
casefold() str.casefoldに同じ
upper() str.upperに同じ
find() str.findに同じ
rfind() str.rfindに同じ
index() str.indexに同じ
rindex() str.rindexに同じ
capitalize() str.capitalizeに同じ
swapcase() str.swapcaseに同じ
normalize() Unicode 標準形式を返す。unicodedata.nnormalizeに同じ
translate() str.translateに同じ
isalnum() str.isalnumに同じ
isalpha() str.isalphaに同じ
isdigit() str.isdigitに同じ
isspace() str.isspaceに同じ
islower() str.islowerに同じ
isupper() str.isupperに同じ
istitle() str.istitleに同じ
isnumeric() str.isnumericに同じ
isdecimal() str.isdecimalに同じ
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2