Работа с текстовыми данными#
Текстовые типы данных#
Существует два способа хранения текстовых данных в pandas:
object-dtype массив NumPy.StringDtypeрасширенный тип.
Мы рекомендуем использовать StringDtype для хранения текстовых данных.
До pandas 1.0, object dtype был единственным вариантом. Это было неудачно по многим причинам:
Вы можете случайно сохранить смесь строк и не-строк в
objectмассив dtype. Лучше иметь выделенный dtype.objectdtype нарушает операции, специфичные для dtype, такие какDataFrame.select_dtypes(). Нет чёткого способа выбрать просто текст, исключая нетекстовые, но все еще столбцы типа object.При чтении кода содержимое
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
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
Или astype после Series или DataFrame создается
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" как тип данных для нестроковых данных, и он будет преобразован в string dtype:
In [7]: s = pd.Series(["a", 2, np.nan], dtype="string")
In [8]: s
Out[8]:
0 a
1 2
2
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
dtype: Int64
In [12]: s2 = s1.astype("string")
In [13]: s2
Out[13]:
0 1
1 2
2
dtype: string
In [14]: type(s2[0])
Out[14]: str
Различия в поведении#
Это места, где поведение StringDtype объекты отличаются от
object dtype
Для
StringDtype, методы доступа к строкам которые возвращают числовой вывод всегда будет возвращать целочисленный тип данных с поддержкой NULL, а не тип int или float в зависимости от наличия значений NA. Методы, возвращающие логический вывод будет возвращать nullable boolean dtype.In [15]: s = pd.Series(["a", None, "b"], dtype="string") In [16]: s Out[16]: 0 a 1
2 b dtype: string In [17]: s.str.count("a") Out[17]: 0 1 1 2 0 dtype: Int64 In [18]: s.dropna().str.count("a") Out[18]: 0 1 2 0 dtype: Int64 Оба вывода являются
Int64dtype. Сравните с object-dtypeIn [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 выходной тип данных — float64. Аналогично для методов, возвращающих булевы значения.
In [22]: s.str.isdigit() Out[22]: 0 False 1
2 False dtype: boolean In [23]: s.str.match("a") Out[23]: 0 True 1 2 False dtype: boolean
Некоторые строковые методы, такие как
Series.str.decode()недоступны наStringArrayпотому чтоStringArrayсодержит только строки, а не байты.В операциях сравнения,
arrays.StringArrayиSeriesподдерживается с помощьюStringArrayвернет объект сBooleanDtype, а неboolтип данных object. Пропущенные значения вStringArrayбудет распространяться в операциях сравнения, а не всегда сравниваться неравными, какnumpy.nan.
Все остальное, что следует в остальной части этого документа, применяется одинаково к
string и object тип данных.
Строковые методы#
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
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
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
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 а затем использовать .str. или .dt. по этому поводу.
Разница в производительности возникает из-за того, что для Series типа category, строковые операции выполняются на .categories и не на каждом элементе
Series.
Обратите внимание, что Series типа category со строкой .categories имеет
некоторые ограничения по сравнению с Series типа строка (например, вы не можете складывать строки
друг с другом: s + " " + s не будет работать, если s является Series типа category). Также,
.str методы, которые работают с элементами типа list недоступны на таком
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
3 [f, g, h]
dtype: object
Элементы в разделенных списках можно получить с помощью get или [] обозначение:
In [40]: s2.str.split("_").str.get(1)
Out[40]:
0 b
1 d
2
3 g
dtype: object
In [41]: s2.str.split("_").str[1]
Out[41]:
0 b
1 d
2
3 g
dtype: object
Легко расширить это для возврата DataFrame с помощью expand.
In [42]: s2.str.split("_", expand=True)
Out[42]:
0 1 2
0 a b c
1 c d e
2
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
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
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
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
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
4
dtype: string
In [50]: s4.str.replace(".", "a", regex=True)
Out[50]:
0 aaa
1 a
2 a
3
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
The replace метод также может принимать вызываемый объект в качестве замены. Он вызывается на каждом pat используя re.sub(). Вызываемый объект должен ожидать один
позиционный аргумент (объект регулярного выражения) и возвращать строку.
# 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
dtype: string
# Using regex groups
In [57]: pat = r"(?P\w+) (?P\w+) (?P\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
dtype: string
The 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
7 XX-XX BA
8 XX-XX
9 XX-XX t
dtype: string
Включая flags аргумент при вызове replace с компилированным
объектом регулярного выражения вызовет исключение 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 имеет тот же эффект, что и str.removeprefix и str.removesuffix добавлено в Python 3.9 <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
Конкатенация#
Существует несколько способов объединить Series или Index, либо с самим собой, либо с другими, все на основе cat(),
соотв. Index.str.cat.
Конкатенация одного 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
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 также может быть двумерным. В этом случае количество строк должно соответствовать длине вызывающего 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 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 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)
могут быть объединены в контейнер, подобный списку (включая итераторы, 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
Если используется join='right' для спискообразного объекта из others который содержит разные индексы,
объединение этих индексов будет использоваться в качестве основы для окончательной конкатенации:
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
6 C
7 d
8 c
dtype: string
In [105]: s.str[1]
Out[105]:
0
1
2
3 a
4 a
5
6 A
7 o
8 a
dtype: string
Извлечение подстрок#
Извлечь первое совпадение в каждом субъекте (extract)#
The extract метод принимает регулярное выражение с хотя бы одной
группой захвата.
Извлечение регулярного выражения с более чем одной группой возвращает 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
Элементы, которые не совпадают, возвращают строку, заполненную NaN. Таким образом,
Series из неупорядоченных строк может быть "преобразована" в Series
или DataFrame с аналогичным индексом из очищенных или более полезных строк, без
необходимости get() для доступа к кортежам или re.match объектов.
Тип данных результата всегда object, даже если совпадение не найдено и
результат содержит только NaN.
Именованные группы, такие как
In [107]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(
.....: r"(?P[ab])(?P\d)" , expand=False
.....: )
.....:
Out[107]:
letter digit
0 a 1
1 b 2
2
и необязательные группы, такие как
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 3
также может использоваться. Обратите внимание, что любые имена групп захвата в регулярном выражении будут использоваться для имён столбцов; в противном случае будут использоваться номера групп захвата.
Извлечение регулярного выражения с одной группой возвращает DataFrame
с одним столбцом, если expand=True.
In [109]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"[ab](\d)", expand=True)
Out[109]:
0
0 1
1 2
2
Возвращает Series, если expand=False.
In [110]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"[ab](\d)", expand=False)
Out[110]:
0 1
1 2
2
dtype: string
Вызов на Index с регулярным выражением, содержащим ровно одну группу захвата
возвращает DataFrame с одним столбцом, если expand=True.
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[a-zA-Z])" , expand=True)
Out[113]:
letter
0 A
1 B
2 C
Возвращает Index if expand=False.
In [114]: s.index.str.extract("(?P[a-zA-Z])" , expand=False)
Out[114]: Index(['A', 'B', 'C'], dtype='object', name='letter')
Вызов на Index с регулярным выражением, содержащим более одной группы захвата, возвращает DataFrame if expand=True.
In [115]: s.index.str.extract("(?P[a-zA-Z])([0-9]+)" , expand=True)
Out[115]:
letter 1
0 A 11
1 B 22
2 C 33
Вызывает ValueError if expand=False.
In [116]: s.index.str.extract("(?P[a-zA-Z])([0-9]+)" , expand=False)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[116], line 1
----> 1 s.index.str.extract("(?P[a-zA-Z])([0-9]+)" , expand=False)
File ~/work/pandas/pandas/pandas/core/strings/accessor.py:140, in forbid_nonstring_types.._forbid_nonstring_types..wrapper (self, *args, **kwargs)
135 msg = (
136 f"Cannot use .str.{func_name} with values of "
137 f"inferred dtype '{self._inferred_dtype}'."
138 )
139 raise TypeError(msg)
--> 140 return func(self, *args, **kwargs)
File ~/work/pandas/pandas/pandas/core/strings/accessor.py:2771, in StringMethods.extract(self, pat, flags, expand)
2768 raise ValueError("pattern contains no capture groups")
2770 if not expand and regex.groups > 1 and isinstance(self._data, ABCIndex):
-> 2771 raise ValueError("only one regex group is supported with Index")
2773 obj = self._data
2774 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[a-z])(?P[0-9])"
In [120]: s.str.extract(two_groups, expand=True)
Out[120]:
letter digit
A a 1
B b 1
C c 1
the extractall метод возвращает каждое совпадение. Результат
extractall всегда является DataFrame с MultiIndex по его
строкам. Последний уровень 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 имеет ровно одно совпадение,
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. Он возвращает DataFrame который имеет
такой же результат, как Series.str.extractall с индексом по умолчанию (начинается с 0).
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 проверяет, есть ли совпадение регулярного выражения в любой позиции строки.
Соответствующие функции в re пакет для этих трёх режимов сопоставления:
re.fullmatch,
re.match, и
re.search,
соответственно.
Методы, такие как match, fullmatch, contains, startswith, и
endswith занимать дополнительный na аргумент, чтобы пропущенные значения могли рассматриваться
как True или False:
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
String 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. Эквивалентно |
|
Эквивалентно |
|
Эквивалентно |
|
Эквивалентно |
|
Эквивалентно |
|
Эквивалентно |
|
Эквивалентно |
|
Эквивалентно |
|
Эквивалентно |
|
Эквивалентно |
|
Эквивалентно |