Spec-Zone.ru › pandas 1

Работа с текстовыми данными

Типы текстовых данных

Новое в версии 1.0.0.

Существует два способа хранения текстовых данных в pandas:

  1. object - массив NumPy.

  2. StringDtype тип расширения.

Рекомендуется использовать StringDtype для хранения текстовых данных.

До pandas 1.0, object тип был единственным вариантом. Это было неудобно по многим причинам:

  1. Вы можете случайно сохранить смесь строк и нестроковых значений в массиве типа object. Лучше иметь выделенный тип.

  2. object тип нарушает операции, специфичные для типа, такие как DataFrame.select_dtypes(). Нет ясного способа выбрать только текст, исключая нетекстовые, но все же столбцы типа object.

  3. При чтении кода содержимое массива типа object менее понятно, чем 'string'.

В настоящее время производительность массивов типа object строк и arrays.StringArray примерно одинакова. Ожидается, что будущие улучшения значительно повысят производительность и снизят нагрузку на память для StringArray.

Предупреждение

StringArray в настоящее время считается экспериментальным. Реализация и части API могут быть изменены без предупреждения.

Для обратной совместимости object тип остается по умолчанию, который мы используем для вывода списка строк.

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

Изменено в версии 1.1.0.

Вы также можете использовать StringDtype/"string" как тип данных для нестроковых данных, и он будет преобразован в string тип:

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

  1. Для StringDtype, методы доступа к строкам, возвращающие числовые значения, всегда будут возвращать тип nullable integer, а не int или float, в зависимости от наличия значений NA. Методы, возвращающие булевы значения, будут возвращать тип nullable boolean.

    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 тип. Сравните с object-типом

    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 тип результата — 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
    
  1. Некоторые строковые методы, такие как Series.str.decode(), недоступны для StringArray, потому что StringArray содержит только строки, а не байты.

  2. В операциях сравнения arrays.StringArray и Series на основе StringArray вернут объект с BooleanDtype, а не объект типа bool . Пропущенные значения в StringArray будут распространяться в операциях сравнения, а не всегда сравниваться как неравные, как numpy.nan.

Все остальное, что следует в остальной части этого документа, одинаково относится к string и object типу.

Строковые методы

Серии и индексы оснащены набором методов обработки строк, которые облегчают работу с каждым элементом массива. Возможно, самое важное, что эти методы автоматически исключают пропущенные/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')

Строковые методы в индексе особенно полезны для очистки или преобразования столбцов 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.<method> или .dt.<property> на этом. Разница в производительности обусловлена тем, что для Series типа category строковые операции выполняются над .categories , а не над каждым элементом Series.

Обратите внимание, что Series типа category со строковыми .categories имеет некоторые ограничения по сравнению со строкой типа Series (например, вы не можете складывать строки друг с другом: s + " " + s не будет работать, если s — это Series типа category). Кроме того, методы .str , которые работают с элементами типа list , недоступны в таком Series.

Предупреждение

До версии 0.25.0 атрибут .str выполнял только самые базовые проверки типа. Начиная с версии 0.25.0, тип 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

Легко расширить это, чтобы вернуть DataFrame, используя expand.

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

Предупреждение

При работе с регулярными выражениями необходимо соблюдать осторожность! В настоящее время поведение заключается в том, что шаблоны с одним символом обрабатываются как литеральные строки, даже когда regex установлено в True. Это поведение устарело и будет удалено в будущей версии, чтобы ключевое слово regex всегда учитывалось.

Изменено в версии 1.2.0.

Если вам нужна буквальная замена строки (эквивалентная str.replace()), можно установить необязательный параметр regex в значение False, а не экранировать каждый символ. В этом случае и pat, и repl должны быть строками:

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

# These lines are equivalent
In [49]: dollars.str.replace(r"-\$", "-", regex=True)
Out[49]: 
0         12
1        -10
2    $10,000
dtype: string

In [50]: dollars.str.replace("-$", "-", regex=False)
Out[50]: 
0         12
1        -10
2    $10,000
dtype: string

Метод replace также может принимать вызываемую функцию в качестве замены. Она вызывается для каждого pat с использованием re.sub(). Вызываемая функция должна принимать один позиционный аргумент (объект регулярного выражения) и возвращать строку.

# Reverse every lowercase alphabetic word
In [51]: pat = r"[a-z]+"

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

In [53]: pd.Series(["foo 123", "bar baz", np.nan], dtype="string").str.replace(
   ....:     pat, repl, regex=True
   ....: )
   ....: 
Out[53]: 
0    oof 123
1    rab zab
2       <NA>
dtype: string

# Using regex groups
In [54]: pat = r"(?P<one>\w+) (?P<two>\w+) (?P<three>\w+)"

In [55]: def repl(m):
   ....:     return m.group("two").swapcase()
   ....: 

In [56]: pd.Series(["Foo Bar Baz", np.nan], dtype="string").str.replace(
   ....:     pat, repl, regex=True
   ....: )
   ....: 
Out[56]: 
0     bAR
1    <NA>
dtype: string

Метод replace также принимает скомпилированный объект регулярного выражения из re.compile() в качестве шаблона. Все флаги должны быть включены в скомпилированный объект регулярного выражения.

In [57]: import re

In [58]: regex_pat = re.compile(r"^.a|dog", flags=re.IGNORECASE)

In [59]: s3.str.replace(regex_pat, "XX-XX ", regex=True)
Out[59]: 
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

Включение аргумента flags при вызове replace с скомпилированным объектом регулярного выражения вызовет ValueError.

In [60]: 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 [61]: s = pd.Series(["str_foo", "str_bar", "no_prefix"])

In [62]: s.str.removeprefix("str_")
Out[62]: 
0          foo
1          bar
2    no_prefix
dtype: object

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

In [64]: s.str.removesuffix("_str")
Out[64]: 
0          foo
1          bar
2    no_suffix
dtype: object

Конкатенация

Существует несколько способов конкатенации Series или Index, как с самими собой, так и с другими, все основанные на cat(), соответственно Index.str.cat.

Конкатенация одного Series в строку

Содержимое Series (или Index) можно конкатенировать:

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

In [66]: s.str.cat(sep=",")
Out[66]: 'a,b,c,d'

Если не указано, ключевое слово sep для разделителя по умолчанию устанавливается в пустую строку, sep='':

In [67]: s.str.cat()
Out[67]: 'abcd'

По умолчанию пропущенные значения игнорируются. Используя na_rep, им можно присвоить представление:

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

In [69]: t.str.cat(sep=",")
Out[69]: 'a,b,d'

In [70]: t.str.cat(sep=",", na_rep="-")
Out[70]: 'a,b,-,d'

Конкатенация Series и чего-то похожего на список в Series

Первый аргумент к cat() может быть объектом, похожим на список, при условии, что его длина соответствует длине вызываемого Series (или Index).

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

Пропущенные значения с любой стороны приведут к пропущенным значениям в результате, за исключением случая, когда указан na_rep:

In [72]: s.str.cat(t)
Out[72]: 
0      aa
1      bb
2    <NA>
3      dd
dtype: string

In [73]: s.str.cat(t, na_rep="-")
Out[73]: 
0    aa
1    bb
2    c-
3    dd
dtype: string

Конкатенация Series и чего-то похожего на массив в Series

Параметр others также может быть двумерным. В этом случае количество строк должно соответствовать длинам вызываемого Series (или Index).

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

In [75]: s
Out[75]: 
0    a
1    b
2    c
3    d
dtype: string

In [76]: d
Out[76]: 
      0  1
0     a  a
1     b  b
2  <NA>  c
3     d  d

In [77]: s.str.cat(d, na_rep="-")
Out[77]: 
0    aaa
1    bbb
2    c-c
3    ddd
dtype: string

Конкатенация Series и индексированного объекта в Series с выравниванием

Для конкатенации с Series или DataFrame, возможно выравнивание индексов перед конкатенацией, установив ключевое слово join.

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

In [79]: s
Out[79]: 
0    a
1    b
2    c
3    d
dtype: string

In [80]: u
Out[80]: 
1    b
3    d
0    a
2    c
dtype: string

In [81]: s.str.cat(u)
Out[81]: 
0    aa
1    bb
2    cc
3    dd
dtype: string

In [82]: s.str.cat(u, join="left")
Out[82]: 
0    aa
1    bb
2    cc
3    dd
dtype: string

Предупреждение

Если ключевое слово join не передано, метод cat() в настоящее время вернется к поведению до версии 0.23.0 (т. е. без выравнивания), но будет возбуждено исключение FutureWarning, если какие-либо из участвующих индексов отличаются, так как это значение по умолчанию изменится на join='left' в будущей версии.

Обычные параметры доступны для join (один из 'left', 'outer', 'inner', 'right'). В частности, выравнивание также означает, что разные длины больше не должны совпадать.

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

In [84]: s
Out[84]: 
0    a
1    b
2    c
3    d
dtype: string

In [85]: v
Out[85]: 
-1    z
 0    a
 1    b
 3    d
 4    e
dtype: string

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

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

То же выравнивание можно использовать, когда others является DataFrame:

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

In [89]: s
Out[89]: 
0    a
1    b
2    c
3    d
dtype: string

In [90]: f
Out[90]: 
      0  1
3     d  d
2  <NA>  c
1     b  b
0     a  a

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

Конкатенация Series и многих объектов в Series

Несколько элементов, похожих на массивы (в частности: Series, Index, и одномерные варианты np.ndarray могут быть объединены в контейнер, похожий на список (включая итераторы, dict-представления и т. д.).

In [92]: s
Out[92]: 
0    a
1    b
2    c
3    d
dtype: string

In [93]: u
Out[93]: 
1    b
3    d
0    a
2    c
dtype: string

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

Все элементы без индекса (например, np.ndarray) в переданном спископодобном объекте должны быть одинаковой длины с вызываемым Series (или Index). Однако Series и Index могут иметь произвольную длину (при условии, что выравнивание не отключено с помощью join=None):

In [95]: v
Out[95]: 
-1    z
 0    a
 1    b
 3    d
 4    e
dtype: string

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

Если используется join='right' на спископодобном объекте others, содержащем разные индексы, объединение этих индексов будет использоваться в качестве основы для конечной конкатенации:

In [97]: u.loc[[3]]
Out[97]: 
3    d
dtype: string

In [98]: v.loc[[-1, 0]]
Out[98]: 
-1    z
 0    a
dtype: string

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

Индексация с помощью .str

Можно использовать обозначение [] для прямой индексации по позиционным местоположениям. Если индексировать за пределами строки, результатом будет NaN.

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

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

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

Извлечение подстрок

Извлечь первое совпадение в каждом объекте (extract)

Предупреждение

До версии 0.23 аргумент expand метода extract по умолчанию был False. Когда expand=False, метод expand возвращал Series, Index, или DataFrame, в зависимости от объекта и шаблона регулярного выражения. Когда expand=True, он всегда возвращал DataFrame, что более согласованно и менее запутанно с точки зрения пользователя. expand=True является значением по умолчанию с версии 0.23.0.

Метод extract принимает регулярное выражение с по крайней мере одной группой захвата.

Извлечение регулярного выражения с более чем одной группой возвращает DataFrame с одним столбцом на каждую группу.

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

Элементы, не соответствующие шаблону, возвращают строку, заполненную NaN. Таким образом, ряд неупорядоченных строк можно «преобразовать» в аналогичный индексированный ряд или DataFrame очищенных или более полезных строк без необходимости get() для доступа к кортежам или re.match объектам. Тип данных результата всегда object, даже если совпадений не найдено, и результат содержит только NaN.

Именованные группы, такие как

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

и необязательные группы, такие как

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

также могут быть использованы. Обратите внимание, что любые имена групп захвата в регулярном выражении будут использоваться в качестве имён столбцов; в противном случае будут использоваться номера групп захвата.

Извлечение регулярного выражения с одной группой возвращает DataFrame с одним столбцом, если expand=True.

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

Возвращает Series, если expand=False.

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

Вызов Index с регулярным выражением с ровно одной группой захвата возвращает DataFrame с одним столбцом, если expand=True.

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

In [109]: s
Out[109]: 
A11    a1
B22    b2
C33    c3
dtype: string

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

Возвращает Series, если expand=False.

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

Вызов Index с регулярным выражением с более чем одной группой захвата возвращает DataFrame если expand=True.

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

Возникает ValueError, если expand=False.

>>> 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 группа

Индекс

Индекс

ValueError

Series

Series

DataFrame

Извлечь все совпадения в каждом объекте (extractall)

В отличие от extract (возвращающего только первое совпадение),

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

In [114]: s
Out[114]: 
A    a1a2
B      b1
C      c1
dtype: string

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

In [116]: s.str.extract(two_groups, expand=True)
Out[116]: 
  letter digit
A      a     1
B      b     1
C      c     1

метод extractall возвращает каждое совпадение. Результат extractall всегда DataFrame с MultiIndex в строках. Последний уровень MultiIndex назван match и указывает порядок в объекте.

In [117]: s.str.extractall(two_groups)
Out[117]: 
        letter digit
  match             
A 0          a     1
  1          a     2
B 0          b     1
C 0          c     1

Когда каждая строка объекта в Series имеет ровно одно совпадение,

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

In [119]: s
Out[119]: 
0    a3
1    b3
2    c2
dtype: string

тогда extractall(pat).xs(0, level='match') даёт тот же результат, что и extract(pat).

In [120]: extract_result = s.str.extract(two_groups, expand=True)

In [121]: extract_result
Out[121]: 
  letter digit
0      a     3
1      b     3
2      c     2

In [122]: extractall_result = s.str.extractall(two_groups)

In [123]: extractall_result
Out[123]: 
        letter digit
  match             
0 0          a     3
1 0          b     3
2 0          c     2

In [124]: extractall_result.xs(0, level="match")
Out[124]: 
  letter digit
0      a     3
1      b     3
2      c     2

Index также поддерживает .str.extractall. Возвращает DataFrame, дающий тот же результат, что и DataFrame с индексом по умолчанию (начинается с 0).

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

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

Проверка строк на соответствие или содержащие шаблон

Можно проверить, содержат ли элементы шаблон:

In [127]: pattern = r"[0-9][a-z]"

In [128]: pd.Series(
   .....:     ["1", "2", "3a", "3b", "03c", "4dx"],
   .....:     dtype="string",
   .....: ).str.contains(pattern)
   .....: 
Out[128]: 
0    False
1    False
2     True
3     True
4     True
5     True
dtype: boolean

Или соответствуют ли элементы шаблону:

In [129]: pd.Series(
   .....:     ["1", "2", "3a", "3b", "03c", "4dx"],
   .....:     dtype="string",
   .....: ).str.match(pattern)
   .....: 
Out[129]: 
0    False
1    False
2     True
3     True
4    False
5     True
dtype: boolean

Введено в версии 1.1.0.

In [130]: pd.Series(
   .....:     ["1", "2", "3a", "3b", "03c", "4dx"],
   .....:     dtype="string",
   .....: ).str.fullmatch(pattern)
   .....: 
Out[130]: 
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 [131]: s4 = pd.Series(
   .....:     ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
   .....: )
   .....: 

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

Создание индикаторных переменных

Вы можете извлечь фиктивные переменные из столбцов строк. Например, если они разделены '|':

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

In [134]: s.str.get_dummies(sep="|")
Out[134]: 
   a  b  c
0  1  0  0
1  1  1  0
2  0  0  0
3  1  0  1

Строковые Index также поддерживают get_dummies, который возвращает MultiIndex.

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

In [136]: idx.str.get_dummies(sep="|")
Out[136]: 
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()

Объединение строк в каждом элементе Series с указанным разделителем

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()

Замена среза в каждой строке заданным значением

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()

Возвращает нормальную форму Юникода. Эквивалентно unicodedata.normalize

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

© 2008–2022, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team
Licensed under the 3-clause BSD License.
https://pandas.pydata.org/pandas-docs/version/1.5.0/user_guide/text.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API