Spec-Zone.ru › pandas 0.18

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

Ряды и индексы оснащены набором методов обработки строк, которые облегчают работу с каждым элементом массива. Возможно, самое важное, что эти методы автоматически исключают пропущенные/NA значения. К ним можно получить доступ через атрибут str и, как правило, они имеют названия, соответствующие эквивалентным (скалярным) встроенным методам строк:

In [1]: s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])

In [2]: s.str.lower()
Out[2]: 
0       a
1       b
2       c
3    aaba
4    baca
5     NaN
6    caba
7     dog
8     cat
dtype: object

In [3]: s.str.upper()
Out[3]: 
0       A
1       B
2       C
3    AABA
4    BACA
5     NaN
6    CABA
7     DOG
8     CAT
dtype: object

In [4]: s.str.len()
Out[4]: 
0    1.0
1    1.0
2    1.0
3    4.0
4    4.0
5    NaN
6    4.0
7    3.0
8    3.0
dtype: float64
In [5]: idx = pd.Index([' jack', 'jill ', ' jesse ', 'frank'])

In [6]: idx.str.strip()
Out[6]: Index([u'jack', u'jill', u'jesse', u'frank'], dtype='object')

In [7]: idx.str.lstrip()
Out[7]: Index([u'jack', u'jill ', u'jesse ', u'frank'], dtype='object')

In [8]: idx.str.rstrip()
Out[8]: Index([u' jack', u'jill', u' jesse', u'frank'], dtype='object')

Методы строк в Индексе особенно полезны для очистки или преобразования столбцов DataFrame. Например, у вас могут быть столбцы с начальными или конечными пробелами:

In [9]: df = pd.DataFrame(randn(3, 2), columns=[' Column A ', ' Column B '],
   ...:                   index=range(3))
   ...: 

In [10]: df
Out[10]: 
    Column A    Column B 
0    0.017428    0.039049
1   -2.240248    0.847859
2   -1.342107    0.368828

Поскольку df.columns — это объект Index, мы можем использовать аксессор .str

In [11]: df.columns.str.strip()
Out[11]: Index([u'Column A', u'Column B'], dtype='object')

In [12]: df.columns.str.lower()
Out[12]: Index([u' column a ', u' column b '], dtype='object')

Эти методы строк можно затем использовать для очистки столбцов по мере необходимости. Здесь мы удаляем начальные и конечные пробелы, приводя все имена к нижнему регистру и заменяя оставшиеся пробелы символами подчеркивания:

In [13]: df.columns = df.columns.str.strip().str.lower().str.replace(' ', '_')

In [14]: df
Out[14]: 
   column_a  column_b
0  0.017428  0.039049
1 -2.240248  0.847859
2 -1.342107  0.368828

Примечание

Если у вас 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.

Разделение и замена строк

Методы, такие как split возвращают Series списков:

In [15]: s2 = pd.Series(['a_b_c', 'c_d_e', np.nan, 'f_g_h'])

In [16]: s2.str.split('_')
Out[16]: 
0    [a, b, c]
1    [c, d, e]
2          NaN
3    [f, g, h]
dtype: object

Элементы в списках разделения могут быть доступны с использованием обозначения get или []

In [17]: s2.str.split('_').str.get(1)
Out[17]: 
0      b
1      d
2    NaN
3      g
dtype: object

In [18]: s2.str.split('_').str[1]
Out[18]: 
0      b
1      d
2    NaN
3      g
dtype: object

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

In [19]: s2.str.split('_', expand=True)
Out[19]: 
     0     1     2
0    a     b     c
1    c     d     e
2  NaN  None  None
3    f     g     h

Также возможно ограничить количество разделений:

In [20]: s2.str.split('_', expand=True, n=1)
Out[20]: 
     0     1
0    a   b_c
1    c   d_e
2  NaN  None
3    f   g_h

rsplit аналогично split, за исключением того, что он работает в обратном направлении, т. е. от конца строки к началу строки:

In [21]: s2.str.rsplit('_', expand=True, n=1)
Out[21]: 
     0     1
0  a_b     c
1  c_d     e
2  NaN  None
3  f_g     h

Методы, такие как replace и findall принимают также регулярные выражения:

In [22]: s3 = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca',
   ....:                '', np.nan, 'CABA', 'dog', 'cat'])
   ....: 

In [23]: s3
Out[23]: 
0       A
1       B
2       C
3    Aaba
4    Baca
5        
6     NaN
7    CABA
8     dog
9     cat
dtype: object

In [24]: s3.str.replace('^.a|dog', 'XX-XX ', case=False)
Out[24]: 
0           A
1           B
2           C
3    XX-XX ba
4    XX-XX ca
5            
6         NaN
7    XX-XX BA
8      XX-XX 
9     XX-XX t
dtype: object

Необходимо соблюдать осторожность, учитывая смысл регулярных выражений! Например, следующий код вызовет проблемы из-за значения регулярного выражения $:

# Consider the following badly formatted financial data
In [25]: dollars = pd.Series(['12', '-$10', '$10,000'])

# This does what you'd naively expect:
In [26]: dollars.str.replace('$', '')
Out[26]: 
0        12
1       -10
2    10,000
dtype: object

# But this doesn't:
In [27]: dollars.str.replace('-$', '-')
Out[27]: 
0         12
1       -$10
2    $10,000
dtype: object

# We need to escape the special character (for >1 len patterns)
In [28]: dollars.str.replace(r'-\$', '-')
Out[28]: 
0         12
1        -10
2    $10,000
dtype: object

Индексирование с .str

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

In [29]: s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan,
   ....:                'CABA', 'dog', 'cat'])
   ....: 

In [30]: s.str[0]
Out[30]: 
0      A
1      B
2      C
3      A
4      B
5    NaN
6      C
7      d
8      c
dtype: object

In [31]: s.str[1]
Out[31]: 
0    NaN
1    NaN
2    NaN
3      a
4      a
5    NaN
6      A
7      o
8      a
dtype: object

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

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

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

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

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

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

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

In [32]: pd.Series(['a1', 'b2', 'c3']).str.extract('([ab])(\d)', expand=False)
Out[32]: 
     0    1
0    a    1
1    b    2
2  NaN  NaN

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

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

In [33]: pd.Series(['a1', 'b2', 'c3']).str.extract('(?P<letter>[ab])(?P<digit>\d)', expand=False)
Out[33]: 
  letter digit
0      a     1
1      b     2
2    NaN   NaN

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

In [34]: pd.Series(['a1', 'b2', '3']).str.extract('([ab])?(\d)', expand=False)
Out[34]: 
     0  1
0    a  1
1    b  2
2  NaN  3

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

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

In [35]: pd.Series(['a1', 'b2', 'c3']).str.extract('[ab](\d)', expand=True)
Out[35]: 
     0
0    1
1    2
2  NaN

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

In [36]: pd.Series(['a1', 'b2', 'c3']).str.extract('[ab](\d)', expand=False)
Out[36]: 
0      1
1      2
2    NaN
dtype: object

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

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

In [38]: s
Out[38]: 
A11    a1
B22    b2
C33    c3
dtype: object

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

Он возвращает Index, если expand=False.

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

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

In [41]: s.index.str.extract("(?P<letter>[a-zA-Z])([0-9]+)", expand=True)
Out[41]: 
  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)

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

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

In [42]: s = pd.Series(["a1a2", "b1", "c1"], ["A", "B", "C"])

In [43]: s
Out[43]: 
A    a1a2
B      b1
C      c1
dtype: object

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

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

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

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

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

In [47]: s = pd.Series(['a3', 'b3', 'c2'])

In [48]: s
Out[48]: 
0    a3
1    b3
2    c2
dtype: object

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

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

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

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

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

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

Проверка строк, которые соответствуют или содержат шаблон

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

In [54]: pattern = r'[a-z][0-9]'

In [55]: pd.Series(['1', '2', '3a', '3b', '03c']).str.contains(pattern)
Out[55]: 
0    False
1    False
2    False
3    False
4    False
dtype: bool

или соответствуют ли шаблону:

In [56]: pd.Series(['1', '2', '3a', '3b', '03c']).str.match(pattern, as_indexer=True)
Out[56]: 
0    False
1    False
2    False
3    False
4    False
dtype: bool

Различие между match и contains заключается в строгости: match полагается на строгий re.match, а contains полагается на re.search.

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

В предыдущих версиях match предназначался для извлечения групп, возвращая не очень удобный ряд кортежей. Новый метод extract (описанный в предыдущем разделе) теперь предпочтительнее.

Это старое, устаревшее поведение match по-прежнему является стандартным. Как показано выше, используйте новое поведение, установив as_indexer=True. В этом режиме, match аналогичен contains, возвращая булевый ряд. Новое поведение станет стандартным в будущей версии.

Methods like match, contains, startswith, and endswith take
дополнительный na аргумент, чтобы пропущенные значения можно было рассматривать как True или False:
In [57]: s4 = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])

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

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

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

In [59]: s = pd.Series(['a', 'a|b', np.nan, 'a|c'])

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

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

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

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

In [62]: idx.str.get_dummies(sep='|')
Out[62]: 
MultiIndex(levels=[[0, 1], [0, 1], [0, 1]],
           labels=[[1, 1, 0, 1], [0, 1, 0, 0], [0, 0, 0, 1]],
           names=[u'a', u'b', u'c'])

См. также get_dummies().

Краткое описание методов

Метод Описание
cat() Конкатенация строк
split() Разделение строк по разделителю
rsplit() Разделение строк по разделителю, начиная с конца строки
get() Индексирование каждого элемента (извлечение i-го элемента)
join() Объединение строк в каждом элементе Series с заданным разделителем
get_dummies() Разделение строк по разделителю с возвращением DataFrame фиктивных переменных
contains() Возвращает булевый массив, если каждая строка содержит шаблон/регулярное выражение
replace() Замена вхождений шаблона/регулярного выражения другой строкой
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
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–2012, 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/0.18.1/text.html

Spec-Zone.ru

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