我不是正则表达式专家,最后一个是最难处理的,但以下工作:
In [402]:
df['code'] = df['product'].str.split('-').str[1:].str.join('-').str.findall(r'[A-Z]+').str.join('-').map(df1.set_index('color')['code'])
df
Out[402]:
product code
index
1 a208-BLACK X1001
2 a2008-WHITE X7005
3 x307-PEARL-WHITE X7055
4 aa-b307-WHITE X7005
基本上我在- 上拆分产品代码,并将所有元素放在第一个破折号的右侧。
剩下这个:
In [403]:
df['product'].str.split('-').str[1:]
Out[403]:
index
1 [BLACK]
2 [WHITE]
3 [PEARL, WHITE]
4 [b307, WHITE]
Name: product, dtype: object
然后我把破折号放回去,使用正则表达式只查找大写字母字符,这处理最后一个,再次重新加入。
最后一点是在颜色列上设置索引后在另一个df上调用map,这将对df中的颜色值进行查找并返回相应的代码。
正则表达式并非万无一失,但它适用于您的数据集。
编辑
我现在意识到我们不需要那么多连接:
In [409]:
df['code'] = df['product'].str.findall(r'[A-Z]+').str.join('-').map(df1.set_index('color')['code'])
df
Out[409]:
product code
index
1 a208-BLACK X1001
2 a2008-WHITE X7005
3 x307-PEARL-WHITE X7055
4 aa-b307-WHITE X7005
时间
In [414]:
%%timeit
import re
df['color'] = df['product'].apply(lambda x: re.sub('^[^ALPHA:]*-(.*)', '\\1', x))
pd.merge(df, df1, on='color')
1 loops, best of 3: 4.09 ms per loop
In [416]:
%%timeit
df['code'] = df['product'].str.findall(r'[A-Z]+').str.join('-').map(df1.set_index('color')['code'])
100 loops, best of 3: 1.63 ms per loop
str 方法比使用 lambda 快 2 倍以上,这可能并不令人惊讶,因为 str 方法是矢量化的,就像调用 map 一样。
更新时间
In [7]:
%%timeit
df1['color'] = df1['product'].str.extract(r'-([A-Z-]+)$')
pd.merge(df1, df2)
100 loops, best of 3: 4.51 ms per loop
In [9]:
%%timeit
df1['code'] = df1['product'].str.findall(r'[A-Z]+').str.join('-').map(df2.set_index('color')['code'])
100 loops, best of 3: 3.87 ms per loop
In [10]:
%%timeit
import re
df1['color'] = df1['product'].apply(lambda x: re.sub('^[^ALPHA:]*-(.*)', '\\1', x))
pd.merge(df1, df2, on='color')
100 loops, best of 3: 4.79 ms per loop
所以@unutbu 的回答比@colonel beaveau 的回答要快一些,但在这里使用地图还是更快。
事实上,如果我们将 @unutbu 的正则表达式 str 方法与 map 结合起来,我们会比我原来的方法更快:
In [12]:
%%timeit
df1['product'].str.extract(r'-([A-Z-]+)$').map(df2.set_index('color')['code'])
100 loops, best of 3: 2.17 ms per loop
所以在这里使用map 比合并快近 2 倍