Я хотел бы удалить первые 3 символа из строк в столбце Dataframe, где длина строки> 4

В противном случае они должны остаться прежними.

Например

bloomberg_ticker_y

AIM9
DJEM9 # (should be M9)
FAM9
IXPM9 # (should be M9)

Я могу отфильтровать строки по длине:

merged['bloomberg_ticker_y'].str.len() > 4

И нарезать строки:

merged['bloomberg_ticker_y'].str[-2:]

Но не уверен, как это собрать и применить к моему фрейму данных

Любая помощь была бы признательна.

7
User63164 1 Июл 2019 в 17:28

6 ответов

Лучший ответ

Вы можете использовать понимание списка:

df = pd.DataFrame({'bloomberg_ticker_y' : ['AIM9', 'DJEM9', 'FAM9', 'IXPM9']})

df['new'] = [x[-2:] if len(x)>4 else x for x in df['bloomberg_ticker_y']]

Выход:

  bloomberg_ticker_y   new
0               AIM9  AIM9
1              DJEM9    M9
2               FAM9  FAM9
3              IXPM9    M9
9
vlemaistre 1 Июл 2019 в 14:31

Вы можете использовать numpy.where, чтобы применить условие для выбора фрагментов на основе длины строки.

np.where(df['bloomberg_ticker_y'].str.len() > 4, 
         df['bloomberg_ticker_y'].str[3:], 
         df['bloomberg_ticker_y'])
# array(['AIM9', 'M9', 'FAM9', 'M9'], dtype=object)
df['bloomberg_ticker_sliced'] = (
   np.where(df['bloomberg_ticker_y'].str.len() > 4, 
            df['bloomberg_ticker_y'].str[3:], 
            df['bloomberg_ticker_y']))
df
  bloomberg_ticker_y bloomberg_ticker_sliced
0               AIM9                    AIM9
1              DJEM9                      M9
2               FAM9                    FAM9
3              IXPM9                      M9

Если вам нравится векторизованное решение map, оно

df['bloomberg_ticker_y'].map(lambda x: x[3:] if len(x) > 4 else x)

0    AIM9
1      M9
2    FAM9
3      M9
Name: bloomberg_ticker_y, dtype: object
7
cs95 1 Июл 2019 в 14:31

Вы также можете использовать DataFrame.apply :

import pandas as pd

df = pd.DataFrame({'bloomberg_ticker_y' : ['AIM9', 'DJEM9', 'FAM9', 'IXPM9']})

df['bloomberg_ticker_y'] = df.apply(lambda x: (x['bloomberg_ticker_y'][3:] if len(x['bloomberg_ticker_y']) > 4 else x['bloomberg_ticker_y']) , axis=1)

Выход:

  bloomberg_ticker_y
0               AIM9
1                 M9
2               FAM9
3                 M9
3
Cobra 1 Июл 2019 в 14:48

Увидел довольно большое разнообразие ответов, поэтому решил сравнить их по скорости:

# Create big size test dataframe
df = pd.DataFrame({'bloomberg_ticker_y' : ['AIM9', 'DJEM9', 'FAM9', 'IXPM9']})
df = pd.concat([df]*100000)
df.shape

#Out
(400000, 1)

CS95 # 1 np.where

%%timeit 
np.where(df['bloomberg_ticker_y'].str.len() > 4, 
         df['bloomberg_ticker_y'].str[3:], 
         df['bloomberg_ticker_y'])

Результат:

163 ms ± 12.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

CS95 # 2 векторизованное решение map

%%timeit 
df['bloomberg_ticker_y'].map(lambda x: x[3:] if len(x) > 4 else x)

Результат:

86 ms ± 7.31 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Яту DataFrame.mask

%%timeit
df.bloomberg_ticker_y.mask(df.bloomberg_ticker_y.str.len().gt(4), 
                           other=df.bloomberg_ticker_y.str[-2:])

Результат:

187 ms ± 18.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Vlemaistre list comprehension

%%timeit
[x[-2:] if len(x)>4 else x for x in df['bloomberg_ticker_y']]

Результат:

84.8 ms ± 4.85 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

pault str.replace с regex

%%timeit
df["bloomberg_ticker_y"].str.replace(r".{3,}(?=.{2}$)", "")

Результат:

324 ms ± 17.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Кобра DataFrame.apply

%%timeit
df.apply(lambda x: (x['bloomberg_ticker_y'][3:] if len(x['bloomberg_ticker_y']) > 4 else x['bloomberg_ticker_y']) , axis=1)

Результат:

6.83 s ± 387 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

< Сильный > Заключение

  • Самый быстрый метод - list comprehension, за которым следует векторное решение map.

  • Самый медленный метод - это DataFrame.apply, безусловно (как и ожидалось), за которым следует str.replace с regex

5
Erfan 1 Июл 2019 в 15:12

Другой подход заключается в использовании регулярных выражений:

df["bloomberg_ticker_y"].str.replace(r".{3,}(?=.{2}$)", "")
#0    AIM9
#1      M9
#2    FAM9
#3      M9

Шаблон означает:

  • .{3,}: соответствует 3 или более символам
  • (?=.{2}$): положительный взгляд на ровно 2 символа, за которыми следует конец строки.
2
pault 1 Июл 2019 в 14:40