Удалить частичную строку из фрейма данных с помощью Pandas - PullRequest
0 голосов
/ 07 июня 2018

Если у меня есть такой фрейм данных:

id    str
01    abc_d(a)
02    ab_d(a)
03    abcd_e(a)
04    a_b(a)

Как я могу получить фрейм данных следующим образом?Извините, я создаю этот фрейм данных для представления моих реальных проблем.Спасибо.

id    str
01    d
02    d
03    e
04    b

Ответы [ 4 ]

0 голосов
/ 07 июня 2018

(плохой ответ)

Series.str.split суп

df['str'] = df['str'].str.split('(').str[0].str.split('_').str[-1]    
df

   id str
0   1   d
1   2   d
2   3   e
3   4   b

(менее плохой ответ)

Series.str.extract

df['str'] = df['str'].str.extract(r'_([^_]+)\(', expand=False)
df

   id str
0   1   d
1   2   d
2   3   e
3   4   b

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


(лучший ответ)

re.search со списком комп.

import re

p = re.compile(r'(?<=_)[^_]+(?=\()')
df['str'] = [p.search(x)[0] for x in df['str'].tolist()] 
df

   id str
0   1   d
1   2   d
2   3   e
3   4   b

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


(также лучший ответ)

str.split со списком comp

df['str'] = [
    x.split('(', 1)[0].split('_')[1] for x in df['str'].tolist()
]
df

   id str
0   1   d
1   2   d
2   3   e
3   4   b

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


Производительность

df_test = pd.concat([df] * 10000, ignore_index=True)

%timeit df_test['str'].str.extract(r'_([^_]+)\(', expand=False)
%timeit df_test['str'].str.split('(').str[0].str.split('_').str[-1] 
%timeit [p.search(x)[0] for x in df_test['str'].tolist()] 
%timeit [x.split('(', 1)[0].split('_')[1] for x in df_test['str'].tolist()]

70.4 ms ± 623 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
99.6 ms ± 730 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
31 ms ± 877 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
30 ms ± 431 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)  # fastest but not by much
0 голосов
/ 07 июня 2018

Может быть, вы можете попробовать split аналогично примеру :

df['str'] = df['str'].str.split('_').str.get(1).str[0]

Или

df['str'] = df['str'].str.split('_').str.get(1).str.split('(').str[0]
0 голосов
/ 07 июня 2018

Использование pd.Series.str.split.Специфично для вашего конкретного формата.

df['str'] = df['str'].str.split('_').str[-1].str[0]

print(df)

   id str
0   1   d
1   2   d
2   3   e
3   4   b
0 голосов
/ 07 июня 2018

Использование extract

df['str']=df['str'].str.extract("\_(.*)\(",expand=True) 
df
Out[585]: 
   id str
0   1   d
1   2   d
2   3   e
3   4   b
...