テキストデータの操作#
テキストデータ型#
pandasでは、テキストデータを格納する方法は2つあります。
object
-dtype NumPy配列。StringDtype
拡張型。
テキストデータの格納には、StringDtype
を使用することをお勧めします。
pandas 1.0より前は、object
dtypeが唯一の選択肢でした。これは多くの理由で好ましくありませんでした。
object
dtype配列には、文字列と非文字列が誤って混在してしまう可能性があります。専用のデータ型を使用する方が良いでしょう。object
dtypeは、DataFrame.select_dtypes()
のようなデータ型固有の操作を妨げます。テキストのみを選択し、非テキストだがobject-dtypeの列を除外する明確な方法はありません。コードを読む際に、
object
dtype配列の内容は、'string'
よりも分かりにくいです。
現在、文字列の object
dtype配列と arrays.StringArray
のパフォーマンスはほぼ同じです。今後の拡張により、StringArray
のパフォーマンスが大幅に向上し、メモリオーバーヘッドが削減される予定です。
警告
StringArray
は現在実験的なものとみなされています。実装とAPIの一部は予告なく変更される可能性があります。
後方互換性のために、object
dtypeは、文字列のリストを推論する際のデフォルト型です。
In [1]: pd.Series(["a", "b", "c"])
Out[1]:
0 a
1 b
2 c
dtype: object
string
dtypeを明示的に要求するには、dtype
を指定します。
In [2]: pd.Series(["a", "b", "c"], dtype="string")
Out[2]:
0 a
1 b
2 c
dtype: string
In [3]: pd.Series(["a", "b", "c"], dtype=pd.StringDtype())
Out[3]:
0 a
1 b
2 c
dtype: string
または、Series
または DataFrame
が作成された後に astype
を使用します。
In [4]: s = pd.Series(["a", "b", "c"])
In [5]: s
Out[5]:
0 a
1 b
2 c
dtype: object
In [6]: s.astype("string")
Out[6]:
0 a
1 b
2 c
dtype: string
また、非文字列データに対して StringDtype
/"string"
をdtypeとして使用することもできます。これは string
dtypeに変換されます。
In [7]: s = pd.Series(["a", 2, np.nan], dtype="string")
In [8]: s
Out[8]:
0 a
1 2
2 <NA>
dtype: string
In [9]: type(s[1])
Out[9]: str
または、既存のpandasデータから変換します。
In [10]: s1 = pd.Series([1, 2, np.nan], dtype="Int64")
In [11]: s1
Out[11]:
0 1
1 2
2 <NA>
dtype: Int64
In [12]: s2 = s1.astype("string")
In [13]: s2
Out[13]:
0 1
1 2
2 <NA>
dtype: string
In [14]: type(s2[0])
Out[14]: str
動作の違い#
これらは、StringDtype
オブジェクトの動作が object
dtypeと異なる点です。
StringDtype
の場合、**数値**を出力する 文字列アクセサメソッド は、NA値の有無に応じてintまたはfloat dtypeではなく、常にNull許容整数dtypeを返します。**ブール値**を出力するメソッドは、Null許容ブールdtypeを返します。In [15]: s = pd.Series(["a", None, "b"], dtype="string") In [16]: s Out[16]: 0 a 1 <NA> 2 b dtype: string In [17]: s.str.count("a") Out[17]: 0 1 1 <NA> 2 0 dtype: Int64 In [18]: s.dropna().str.count("a") Out[18]: 0 1 2 0 dtype: Int64
どちらの出力も
Int64
dtypeです。object-dtypeと比較してください。In [19]: s2 = pd.Series(["a", None, "b"], dtype="object") In [20]: s2.str.count("a") Out[20]: 0 1.0 1 NaN 2 0.0 dtype: float64 In [21]: s2.dropna().str.count("a") Out[21]: 0 1 2 0 dtype: int64
NA値が存在する場合、出力dtypeはfloat64です。ブール値を返すメソッドも同様です。
In [22]: s.str.isdigit() Out[22]: 0 False 1 <NA> 2 False dtype: boolean In [23]: s.str.match("a") Out[23]: 0 True 1 <NA> 2 False dtype: boolean
Series.str.decode()
のような一部の文字列メソッドは、StringArray
では使用できません。これは、StringArray
はバイトではなく文字列のみを保持するためです。比較演算では、
arrays.StringArray
とStringArray
によってバッキングされたSeries
は、bool
dtypeオブジェクトではなく、BooleanDtype
を持つオブジェクトを返します。StringArray
内の欠損値は、numpy.nan
のように常に不等号で比較されるのではなく、比較演算で伝播されます。
このドキュメントの残りの部分に記載されている内容は、string
と object
dtypeの両方に等しく適用されます。
文字列メソッド#
SeriesとIndexには、配列の各要素を簡単に操作できる一連の文字列処理メソッドが備わっています。おそらく最も重要なことは、これらのメソッドは欠損値/NA値を自動的に除外することです。これらは str
属性を介してアクセスされ、一般的に対応する(スカラー)組み込み文字列メソッドと一致する名前を持っています。
In [24]: s = pd.Series(
....: ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
....: )
....:
In [25]: s.str.lower()
Out[25]:
0 a
1 b
2 c
3 aaba
4 baca
5 <NA>
6 caba
7 dog
8 cat
dtype: string
In [26]: s.str.upper()
Out[26]:
0 A
1 B
2 C
3 AABA
4 BACA
5 <NA>
6 CABA
7 DOG
8 CAT
dtype: string
In [27]: s.str.len()
Out[27]:
0 1
1 1
2 1
3 4
4 4
5 <NA>
6 4
7 3
8 3
dtype: Int64
In [28]: idx = pd.Index([" jack", "jill ", " jesse ", "frank"])
In [29]: idx.str.strip()
Out[29]: Index(['jack', 'jill', 'jesse', 'frank'], dtype='object')
In [30]: idx.str.lstrip()
Out[30]: Index(['jack', 'jill ', 'jesse ', 'frank'], dtype='object')
In [31]: idx.str.rstrip()
Out[31]: Index([' jack', 'jill', ' jesse', 'frank'], dtype='object')
Indexの文字列メソッドは、DataFrameの列をクリーンアップまたは変換するのに特に役立ちます。たとえば、先頭または末尾に空白がある列がある場合があります。
In [32]: df = pd.DataFrame(
....: np.random.randn(3, 2), columns=[" Column A ", " Column B "], index=range(3)
....: )
....:
In [33]: df
Out[33]:
Column A Column B
0 0.469112 -0.282863
1 -1.509059 -1.135632
2 1.212112 -0.173215
df.columns
はIndexオブジェクトであるため、.str
アクセサを使用できます。
In [34]: df.columns.str.strip()
Out[34]: Index(['Column A', 'Column B'], dtype='object')
In [35]: df.columns.str.lower()
Out[35]: Index([' column a ', ' column b '], dtype='object')
これらの文字列メソッドを使用して、必要に応じて列をクリーンアップできます。ここでは、先頭と末尾の空白を削除し、すべての名前に小文字を使用し、残りの空白をアンダースコアに置き換えています。
In [36]: df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_")
In [37]: df
Out[37]:
column_a column_b
0 0.469112 -0.282863
1 -1.509059 -1.135632
2 1.212112 -0.173215
注意
多くの要素が繰り返される Series
がある場合(つまり、Series
内のユニークな要素の数が Series
の長さよりもはるかに少ない場合)、元の Series
を category
型の Series
に変換してから、.str.<method>
または .dt.<property>
を使用した方が高速になる可能性があります。パフォーマンスの違いは、category
型の Series
の場合、文字列操作が Series
の各要素ではなく .categories
に対して実行されるという事実によるものです。
文字列 .categories
を持つ category
型の Series
は、文字列型の Series
と比較していくつかの制限があることに注意してください(たとえば、文字列を互いに追加することはできません。s
が category
型の Series
の場合、s + " " + s
は機能しません)。また、list
型の要素を操作する .str
メソッドは、そのような Series
では使用できません。
警告
Seriesの型が推論され、許可される型(つまり、文字列)が決定されます。
一般的に、.str
アクセサは文字列に対してのみ機能することを意図しています。ごくわずかな例外を除いて、他の用途はサポートされておらず、後で無効になる可能性があります。
文字列の分割と置換#
split
のようなメソッドは、リストのSeriesを返します。
In [38]: s2 = pd.Series(["a_b_c", "c_d_e", np.nan, "f_g_h"], dtype="string")
In [39]: s2.str.split("_")
Out[39]:
0 [a, b, c]
1 [c, d, e]
2 <NA>
3 [f, g, h]
dtype: object
分割されたリストの要素には、get
または []
表記を使用してアクセスできます。
In [40]: s2.str.split("_").str.get(1)
Out[40]:
0 b
1 d
2 <NA>
3 g
dtype: object
In [41]: s2.str.split("_").str[1]
Out[41]:
0 b
1 d
2 <NA>
3 g
dtype: object
expand
を使用してDataFrameを返すように簡単に拡張できます。
In [42]: s2.str.split("_", expand=True)
Out[42]:
0 1 2
0 a b c
1 c d e
2 <NA> <NA> <NA>
3 f g h
元の Series
が StringDtype
を持つ場合、出力列はすべて StringDtype
になります。
分割数を制限することも可能です。
In [43]: s2.str.split("_", expand=True, n=1)
Out[43]:
0 1
0 a b_c
1 c d_e
2 <NA> <NA>
3 f g_h
rsplit
は、文字列の末尾から先頭に向かって動作するという点を除いて、split
と似ています。
In [44]: s2.str.rsplit("_", expand=True, n=1)
Out[44]:
0 1
0 a_b c
1 c_d e
2 <NA> <NA>
3 f_g h
replace
は、オプションで 正規表現 を使用します。
In [45]: s3 = pd.Series(
....: ["A", "B", "C", "Aaba", "Baca", "", np.nan, "CABA", "dog", "cat"],
....: dtype="string",
....: )
....:
In [46]: s3
Out[46]:
0 A
1 B
2 C
3 Aaba
4 Baca
5
6 <NA>
7 CABA
8 dog
9 cat
dtype: string
In [47]: s3.str.replace("^.a|dog", "XX-XX ", case=False, regex=True)
Out[47]:
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
バージョン 2.0 で変更されました。
regex=True
を指定した単一文字のパターンも正規表現として扱われます。
In [48]: s4 = pd.Series(["a.b", ".", "b", np.nan, ""], dtype="string")
In [49]: s4
Out[49]:
0 a.b
1 .
2 b
3 <NA>
4
dtype: string
In [50]: s4.str.replace(".", "a", regex=True)
Out[50]:
0 aaa
1 a
2 a
3 <NA>
4
dtype: string
文字列のリテラル置換(str.replace()
と同等)を行いたい場合は、各文字をエスケープするのではなく、オプションのregex
パラメータをFalse
に設定できます。この場合、pat
とrepl
はどちらも文字列でなければなりません。
In [51]: dollars = pd.Series(["12", "-$10", "$10,000"], dtype="string")
# These lines are equivalent
In [52]: dollars.str.replace(r"-\$", "-", regex=True)
Out[52]:
0 12
1 -10
2 $10,000
dtype: string
In [53]: dollars.str.replace("-$", "-", regex=False)
Out[53]:
0 12
1 -10
2 $10,000
dtype: string
replace
メソッドは、置換として呼び出し可能オブジェクトも受け取ることができます。これは、re.sub()
を使用して、すべてのpat
で呼び出されます。呼び出し可能オブジェクトは、1つの位置引数(正規表現オブジェクト)を受け取り、文字列を返す必要があります。
# Reverse every lowercase alphabetic word
In [54]: pat = r"[a-z]+"
In [55]: def repl(m):
....: return m.group(0)[::-1]
....:
In [56]: pd.Series(["foo 123", "bar baz", np.nan], dtype="string").str.replace(
....: pat, repl, regex=True
....: )
....:
Out[56]:
0 oof 123
1 rab zab
2 <NA>
dtype: string
# Using regex groups
In [57]: pat = r"(?P<one>\w+) (?P<two>\w+) (?P<three>\w+)"
In [58]: def repl(m):
....: return m.group("two").swapcase()
....:
In [59]: pd.Series(["Foo Bar Baz", np.nan], dtype="string").str.replace(
....: pat, repl, regex=True
....: )
....:
Out[59]:
0 bAR
1 <NA>
dtype: string
replace
メソッドは、re.compile()
からコンパイルされた正規表現オブジェクトをパターンとして受け入れることもできます。すべてのフラグは、コンパイルされた正規表現オブジェクトに含まれている必要があります。
In [60]: import re
In [61]: regex_pat = re.compile(r"^.a|dog", flags=re.IGNORECASE)
In [62]: s3.str.replace(regex_pat, "XX-XX ", regex=True)
Out[62]:
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
が発生します。
In [63]: s3.str.replace(regex_pat, 'XX-XX ', flags=re.IGNORECASE)
---------------------------------------------------------------------------
ValueError: case and flags cannot be set when pat is a compiled regex
removeprefix
とremovesuffix
は、Python 3.9で追加されたstr.removeprefix
とstr.removesuffix
と同じ効果があります <https://docs.python.org/3/library/stdtypes.html#str.removeprefix>`__
バージョン1.4.0の新機能です。
In [64]: s = pd.Series(["str_foo", "str_bar", "no_prefix"])
In [65]: s.str.removeprefix("str_")
Out[65]:
0 foo
1 bar
2 no_prefix
dtype: object
In [66]: s = pd.Series(["foo_str", "bar_str", "no_suffix"])
In [67]: s.str.removesuffix("_str")
Out[67]:
0 foo
1 bar
2 no_suffix
dtype: object
連結#
cat()
、またはIndex.str.cat
に基づいて、Series
またはIndex
を自身または他のものと連結する方法はいくつかあります。
単一のSeriesを文字列に連結する#
Series
(またはIndex
)の内容は連結できます。
In [68]: s = pd.Series(["a", "b", "c", "d"], dtype="string")
In [69]: s.str.cat(sep=",")
Out[69]: 'a,b,c,d'
指定しない場合、区切り文字のキーワードsep
はデフォルトで空の文字列sep=''
になります。
In [70]: s.str.cat()
Out[70]: 'abcd'
デフォルトでは、欠損値は無視されます。na_rep
を使用すると、それらに表現を与えることができます。
In [71]: t = pd.Series(["a", "b", np.nan, "d"], dtype="string")
In [72]: t.str.cat(sep=",")
Out[72]: 'a,b,d'
In [73]: t.str.cat(sep=",", na_rep="-")
Out[73]: 'a,b,-,d'
SeriesとリストのようなものをSeriesに連結する#
cat()
の最初の引数は、呼び出し元のSeries
(またはIndex
)の長さと一致する場合、リストのようなオブジェクトにすることができます。
In [74]: s.str.cat(["A", "B", "C", "D"])
Out[74]:
0 aA
1 bB
2 cC
3 dD
dtype: string
na_rep
が指定されていない限り、どちらかの側の欠損値は、結果にも欠損値をもたらします。
In [75]: s.str.cat(t)
Out[75]:
0 aa
1 bb
2 <NA>
3 dd
dtype: string
In [76]: s.str.cat(t, na_rep="-")
Out[76]:
0 aa
1 bb
2 c-
3 dd
dtype: string
Seriesと配列のようなものをSeriesに連結する#
パラメータothers
は2次元にすることもできます。この場合、行数は呼び出し元のSeries
(またはIndex
)の長さと一致する必要があります。
In [77]: d = pd.concat([t, s], axis=1)
In [78]: s
Out[78]:
0 a
1 b
2 c
3 d
dtype: string
In [79]: d
Out[79]:
0 1
0 a a
1 b b
2 <NA> c
3 d d
In [80]: s.str.cat(d, na_rep="-")
Out[80]:
0 aaa
1 bbb
2 c-c
3 ddd
dtype: string
Seriesとインデックス付きオブジェクトを、位置合わせを行ってSeriesに連結する#
Series
またはDataFrame
との連結では、join
キーワードを設定することにより、連結前にインデックスを調整できます。
In [81]: u = pd.Series(["b", "d", "a", "c"], index=[1, 3, 0, 2], dtype="string")
In [82]: s
Out[82]:
0 a
1 b
2 c
3 d
dtype: string
In [83]: u
Out[83]:
1 b
3 d
0 a
2 c
dtype: string
In [84]: s.str.cat(u)
Out[84]:
0 aa
1 bb
2 cc
3 dd
dtype: string
In [85]: s.str.cat(u, join="left")
Out[85]:
0 aa
1 bb
2 cc
3 dd
dtype: string
join
には通常のオプション('left', 'outer', 'inner', 'right'
のいずれか)を使用できます。特に、位置合わせとは、異なる長さが一致する必要がなくなったことも意味します。
In [86]: v = pd.Series(["z", "a", "b", "d", "e"], index=[-1, 0, 1, 3, 4], dtype="string")
In [87]: s
Out[87]:
0 a
1 b
2 c
3 d
dtype: string
In [88]: v
Out[88]:
-1 z
0 a
1 b
3 d
4 e
dtype: string
In [89]: s.str.cat(v, join="left", na_rep="-")
Out[89]:
0 aa
1 bb
2 c-
3 dd
dtype: string
In [90]: s.str.cat(v, join="outer", na_rep="-")
Out[90]:
-1 -z
0 aa
1 bb
2 c-
3 dd
4 -e
dtype: string
others
がDataFrame
の場合も同じ位置合わせを使用できます。
In [91]: f = d.loc[[3, 2, 1, 0], :]
In [92]: s
Out[92]:
0 a
1 b
2 c
3 d
dtype: string
In [93]: f
Out[93]:
0 1
3 d d
2 <NA> c
1 b b
0 a a
In [94]: s.str.cat(f, join="left", na_rep="-")
Out[94]:
0 aaa
1 bbb
2 c-c
3 ddd
dtype: string
Seriesと多数のオブジェクトをSeriesに連結する#
複数の配列のようなアイテム(具体的には:Series
、Index
、およびnp.ndarray
の1次元バリアント)をリストのようなコンテナ(イテレータ、dict
ビューなど)に組み合わせることができます。
In [95]: s
Out[95]:
0 a
1 b
2 c
3 d
dtype: string
In [96]: u
Out[96]:
1 b
3 d
0 a
2 c
dtype: string
In [97]: s.str.cat([u, u.to_numpy()], join="left")
Out[97]:
0 aab
1 bbd
2 cca
3 ddc
dtype: string
渡されたリストのようなものの中で、インデックスのないすべての要素(例:np.ndarray
)は、呼び出し元のSeries
(またはIndex
)の長さと一致する必要がありますが、Series
とIndex
は任意の長さを持つことができます(join=None
で位置合わせが無効になっていない限り)。
In [98]: v
Out[98]:
-1 z
0 a
1 b
3 d
4 e
dtype: string
In [99]: s.str.cat([v, u, u.to_numpy()], join="outer", na_rep="-")
Out[99]:
-1 -z--
0 aaab
1 bbbd
2 c-ca
3 dddc
4 -e--
dtype: string
異なるインデックスを含むothers
のリストのようなものでjoin='right'
を使用する場合、これらのインデックスの和集合が最終的な連結の基礎として使用されます。
In [100]: u.loc[[3]]
Out[100]:
3 d
dtype: string
In [101]: v.loc[[-1, 0]]
Out[101]:
-1 z
0 a
dtype: string
In [102]: s.str.cat([u.loc[[3]], v.loc[[-1, 0]]], join="right", na_rep="-")
Out[102]:
3 dd-
-1 --z
0 a-a
dtype: string
.str
によるインデックス付け#
[]
表記法を使用して、位置の場所によって直接インデックスを付けることができます。文字列の末尾を超えてインデックスを付けると、結果はNaN
になります。
In [103]: s = pd.Series(
.....: ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
.....: )
.....:
In [104]: s.str[0]
Out[104]:
0 A
1 B
2 C
3 A
4 B
5 <NA>
6 C
7 d
8 c
dtype: string
In [105]: s.str[1]
Out[105]:
0 <NA>
1 <NA>
2 <NA>
3 a
4 a
5 <NA>
6 A
7 o
8 a
dtype: string
部分文字列の抽出#
各対象の最初の一致を抽出する(extract)#
extract
メソッドは、少なくとも1つのキャプチャグループを持つ正規表現を受け入れます。
複数のグループを持つ正規表現を抽出すると、グループごとに1つの列を持つDataFrameが返されます。
In [106]: pd.Series(
.....: ["a1", "b2", "c3"],
.....: dtype="string",
.....: ).str.extract(r"([ab])(\d)", expand=False)
.....:
Out[106]:
0 1
0 a 1
1 b 2
2 <NA> <NA>
一致しない要素は、NaN
で埋められた行を返します。したがって、乱雑な文字列のSeriesは、タプルにアクセスするためのget()
やre.match
オブジェクトを必要とせずに、同様のインデックスを持つSeriesまたはDataFrameに「変換」できます。結果のdtypeは、一致が見つからず、結果にNaN
のみが含まれている場合でも、常にオブジェクトです。
名前付きグループのように
In [107]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(
.....: r"(?P<letter>[ab])(?P<digit>\d)", expand=False
.....: )
.....:
Out[107]:
letter digit
0 a 1
1 b 2
2 <NA> <NA>
オプションのグループのように
In [108]: pd.Series(
.....: ["a1", "b2", "3"],
.....: dtype="string",
.....: ).str.extract(r"([ab])?(\d)", expand=False)
.....:
Out[108]:
0 1
0 a 1
1 b 2
2 <NA> 3
も使用できます。正規表現のキャプチャグループ名は列名に使用されることに注意してください。そうでない場合、キャプチャグループ番号が使用されます。
1つのグループを持つ正規表現を抽出すると、expand=True
の場合、1つの列を持つDataFrame
が返されます。
In [109]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"[ab](\d)", expand=True)
Out[109]:
0
0 1
1 2
2 <NA>
expand=False
の場合、Seriesが返されます。
In [110]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"[ab](\d)", expand=False)
Out[110]:
0 1
1 2
2 <NA>
dtype: string
正確に1つのキャプチャグループを持つ正規表現でIndex
を呼び出すと、expand=True
の場合、1つの列を持つDataFrame
が返されます。
In [111]: s = pd.Series(["a1", "b2", "c3"], ["A11", "B22", "C33"], dtype="string")
In [112]: s
Out[112]:
A11 a1
B22 b2
C33 c3
dtype: string
In [113]: s.index.str.extract("(?P<letter>[a-zA-Z])", expand=True)
Out[113]:
letter
0 A
1 B
2 C
expand=False
の場合、Index
が返されます。
In [114]: s.index.str.extract("(?P<letter>[a-zA-Z])", expand=False)
Out[114]: Index(['A', 'B', 'C'], dtype='object', name='letter')
複数のキャプチャグループを持つ正規表現でIndex
を呼び出すと、expand=True
の場合、DataFrame
が返されます。
In [115]: s.index.str.extract("(?P<letter>[a-zA-Z])([0-9]+)", expand=True)
Out[115]:
letter 1
0 A 11
1 B 22
2 C 33
expand=False
の場合、ValueError
が発生します。
In [116]: s.index.str.extract("(?P<letter>[a-zA-Z])([0-9]+)", expand=False)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[116], line 1
----> 1 s.index.str.extract("(?P<letter>[a-zA-Z])([0-9]+)", expand=False)
File ~/work/pandas/pandas/pandas/core/strings/accessor.py:137, in forbid_nonstring_types.<locals>._forbid_nonstring_types.<locals>.wrapper(self, *args, **kwargs)
132 msg = (
133 f"Cannot use .str.{func_name} with values of "
134 f"inferred dtype '{self._inferred_dtype}'."
135 )
136 raise TypeError(msg)
--> 137 return func(self, *args, **kwargs)
File ~/work/pandas/pandas/pandas/core/strings/accessor.py:2743, in StringMethods.extract(self, pat, flags, expand)
2740 raise ValueError("pattern contains no capture groups")
2742 if not expand and regex.groups > 1 and isinstance(self._data, ABCIndex):
-> 2743 raise ValueError("only one regex group is supported with Index")
2745 obj = self._data
2746 result_dtype = _result_dtype(obj)
ValueError: only one regex group is supported with Index
以下の表は、extract(expand=False)
の動作をまとめたものです(最初の列に入力対象、最初の行に正規表現のグループ数)。
1グループ |
1グループ以上 |
|
Index |
Index |
ValueError |
Series |
Series |
DataFrame |
各対象のすべての一致を抽出する(extractall)#
extract
(最初の一致のみを返す)とは異なり、
In [117]: s = pd.Series(["a1a2", "b1", "c1"], index=["A", "B", "C"], dtype="string")
In [118]: s
Out[118]:
A a1a2
B b1
C c1
dtype: string
In [119]: two_groups = "(?P<letter>[a-z])(?P<digit>[0-9])"
In [120]: s.str.extract(two_groups, expand=True)
Out[120]:
letter digit
A a 1
B b 1
C c 1
extractall
メソッドはすべての一致を返します。extractall
の結果は、常にMultiIndex
を持つDataFrame
です。MultiIndex
の最後のレベルはmatch
という名前で、対象の順序を示します。
In [121]: s.str.extractall(two_groups)
Out[121]:
letter digit
match
A 0 a 1
1 a 2
B 0 b 1
C 0 c 1
Seriesの各対象文字列に一致が1つだけある場合、
In [122]: s = pd.Series(["a3", "b3", "c2"], dtype="string")
In [123]: s
Out[123]:
0 a3
1 b3
2 c2
dtype: string
このとき、extractall(pat).xs(0, level='match')
は extract(pat)
と同じ結果を返します。
In [124]: extract_result = s.str.extract(two_groups, expand=True)
In [125]: extract_result
Out[125]:
letter digit
0 a 3
1 b 3
2 c 2
In [126]: extractall_result = s.str.extractall(two_groups)
In [127]: extractall_result
Out[127]:
letter digit
match
0 0 a 3
1 0 b 3
2 0 c 2
In [128]: extractall_result.xs(0, level="match")
Out[128]:
letter digit
0 a 3
1 b 3
2 c 2
Index
も .str.extractall
をサポートしています。これは、デフォルトのインデックス(0から始まる)を持つ Series.str.extractall
と同じ結果を持つ DataFrame
を返します。
In [129]: pd.Index(["a1a2", "b1", "c1"]).str.extractall(two_groups)
Out[129]:
letter digit
match
0 0 a 1
1 a 2
1 0 b 1
2 0 c 1
In [130]: pd.Series(["a1a2", "b1", "c1"], dtype="string").str.extractall(two_groups)
Out[130]:
letter digit
match
0 0 a 1
1 a 2
1 0 b 1
2 0 c 1
パターンに一致またはパターンを含む文字列のテスト#
要素がパターンを含むかどうかを確認できます
In [131]: pattern = r"[0-9][a-z]"
In [132]: pd.Series(
.....: ["1", "2", "3a", "3b", "03c", "4dx"],
.....: dtype="string",
.....: ).str.contains(pattern)
.....:
Out[132]:
0 False
1 False
2 True
3 True
4 True
5 True
dtype: boolean
または、要素がパターンに一致するかどうか
In [133]: pd.Series(
.....: ["1", "2", "3a", "3b", "03c", "4dx"],
.....: dtype="string",
.....: ).str.match(pattern)
.....:
Out[133]:
0 False
1 False
2 True
3 True
4 False
5 True
dtype: boolean
In [134]: pd.Series(
.....: ["1", "2", "3a", "3b", "03c", "4dx"],
.....: dtype="string",
.....: ).str.fullmatch(pattern)
.....:
Out[134]:
0 False
1 False
2 True
3 True
4 False
5 False
dtype: boolean
注意
match
、fullmatch
、contains
の違いは厳密さです。fullmatch
は文字列全体が正規表現に一致するかどうかをテストします。match
は文字列の最初の文字から始まる正規表現の一致があるかどうかをテストします。contains
は文字列内の任意の位置に正規表現の一致があるかどうかをテストします。
これらの3つの一致モードに対応する re
パッケージの関数は、それぞれ re.fullmatch、re.match、re.search です。
match
、fullmatch
、contains
、startswith
、endswith
などのメソッドは、欠損値を True または False と見なせるように、追加の na
引数を取ります。
In [135]: s4 = pd.Series(
.....: ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
.....: )
.....:
In [136]: s4.str.contains("A", na=False)
Out[136]:
0 True
1 False
2 False
3 True
4 False
5 False
6 True
7 False
8 False
dtype: boolean
インジケーター変数の作成#
文字列の列からダミー変数を抽出できます。たとえば、'|'
で区切られている場合
In [137]: s = pd.Series(["a", "a|b", np.nan, "a|c"], dtype="string")
In [138]: s.str.get_dummies(sep="|")
Out[138]:
a b c
0 1 0 0
1 1 1 0
2 0 0 0
3 1 0 1
文字列 Index
も get_dummies
をサポートしており、MultiIndex
を返します。
In [139]: idx = pd.Index(["a", "a|b", np.nan, "a|c"])
In [140]: idx.str.get_dummies(sep="|")
Out[140]:
MultiIndex([(1, 0, 0),
(1, 1, 0),
(0, 0, 0),
(1, 0, 1)],
names=['a', 'b', 'c'])
get_dummies()
も参照してください。
メソッドの概要#
メソッド |
説明 |
---|---|
文字列を連結する |
|
区切り文字で文字列を分割する |
|
文字列の末尾から区切り文字で文字列を分割する |
|
各要素にインデックスを付ける(i番目の要素を取得する) |
|
Series の各要素の文字列を渡された区切り文字で結合する |
|
区切り文字で文字列を分割し、ダミー変数の DataFrame を返す |
|
各文字列がパターン/正規表現を含む場合、ブール値の配列を返す |
|
パターン/正規表現/文字列の出現を他の文字列、または出現を指定した呼び出し可能オブジェクトの戻り値に置き換える |
|
文字列からプレフィックスを削除する。つまり、文字列がプレフィックスで始まる場合にのみ削除する。 |
|
文字列からサフィックスを削除する。つまり、文字列がサフィックスで終わる場合にのみ削除する。 |
|
値を複製する ( |
|
文字列の左、右、または両側に空白を追加する |
|
|
|
|
|
|
|
|
|
長い文字列を指定された幅より短い行に分割する |
|
Series 内の各文字列をスライスする |
|
各文字列のスライスを渡された値に置き換える |
|
パターンの出現回数をカウントする |
|
各要素に対して |
|
各要素に対して |
|
各文字列のパターン/正規表現のすべての出現のリストを計算する |
|
各要素に対して |
|
各要素に対して |
|
各要素に対して |
|
文字列の長さを計算する |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Unicode 正規形を返す。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|