根据字符串长度对Dataframe列进行切片

时间:2019-07-01 14:28:53

标签: python pandas

我想从字符串长度> 4的Dataframe列中的字符串中删除前3个字符

否则它们应该保持不变。

例如

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:]

但是不确定如何将它们放在一起并应用于我的数据框

任何帮助将不胜感激。

6 个答案:

答案 0 :(得分:8)

您可以使用列表理解:

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

答案 1 :(得分:7)

您可以使用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

答案 2 :(得分:5)

看到了各种各样的答案,因此决定比较它们的速度:

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

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

str.replaceregex

%%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.replaceregex

答案 3 :(得分:3)

您可以使用DataFrame.mask

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

       bloomberg_ticker_y
0               AIM9
1                 M9
2               FAM9
3                 M9

答案 4 :(得分:3)

您也可以使用DataFrame.apply

Trim()

输出:

List<string> centerIds_list = "1LE, 1GE".Split(',').Select(x => x.Trim()).ToList();

答案 5 :(得分:2)

另一种方法是使用正则表达式:

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

该模式的意思是:

  • .{3,}:匹配3个或更多字符
  • (?=.{2}$):积极地期待正好2个字符,然后是字符串的结尾。