使用正则表达式字典填充 Pandas DataFrame 列

3

I have a dataframe like the following:

    GE    GO
1   AD    Weiss
2   KI    Ruby
3   OH    Port
4   ER    Rose
5   KI    Rose
6   JJ    Weiss
7   OH    7UP
8   AD    7UP
9   OP    Coke
10  JJ    Stout

我想根据列GO的值添加一列。我考虑使用字典,但在实际情况下,我需要使用正则表达式来识别部分匹配。例如:

Dic={'Weiss|\wuby|Sto\w+':'Beer', 'Port|Rose':'Wine','\dUP|Coke':'Soda'}

这将会给予:
    GE    GO    OUT
1   AD    Weiss Beer
2   KI    Ruby  Beer
3   OH    Port  Wine
4   ER    Rose  Wine
5   KI    Rose  Wine
6   JJ    Weiss Beer
7   OH    7UP   Soda
8   AD    7UP   Soda
9   OP    Coke  Soda
10  JJ    Stout Beer

这里可以使用lambda函数吗?如何将它转换为正则表达式?提前感谢!

2个回答

6
您可以这样做:
In [253]: df['OUT'] = df[['GO']].replace({'GO':Dic}, regex=True)

In [254]: df
Out[254]:
    GE     GO   OUT
1   AD  Weiss  Beer
2   KI   Ruby  Beer
3   OH   Port  Wine
4   ER   Rose  Wine
5   KI   Rose  Wine
6   JJ  Weiss  Beer
7   OH    7UP  Soda
8   AD    7UP  Soda
9   OP   Coke  Soda
10  JJ  Stout  Beer

有趣的观察 - 在旧版本的Pandas中,Series.map()方法几乎总是比DataFrame.replace()Series.str.replace()方法更快。但在Pandas 0.19.2中,情况有所改善:

In [267]: df = pd.concat([df] * 10**4, ignore_index=True)

In [268]: %timeit df.GO.map(lambda x: next(Dic[k] for k in Dic if re.search(k, x)))
1 loop, best of 3: 1.57 s per loop

In [269]: %timeit df[['GO']].replace({'GO':Dic}, regex=True)
1 loop, best of 3: 895 ms per loop

In [270]: %timeit df.GO.replace(Dic, regex=True)
1 loop, best of 3: 876 ms per loop

In [271]: df.shape
Out[271]: (100000, 2)

1
不等了!太棒了。顺便说一下,df.GO.replace(Dic, regex=True) - piRSquared
当一个值匹配多个正则表达式时会发生什么? - piRSquared
这很美。 - sgrg
@piRSquared,请将 df.GO.replace(Dic, regex=True) 发布为您自己的解决方案 - 它绝对值得! - MaxU - stand with Ukraine
1
@MaxU 我很感激... 但感觉太像你的回答了 :-) - piRSquared
显示剩余4条评论

5

有一个选项是利用re模块和GO列上的map

import re
df['OUT'] = df.GO.map(lambda x: next(Dic[k] for k in Dic if re.search(k, x)))
df

enter image description here

如果没有任何模式与字符串匹配,则会引发错误。 如果存在字符串不匹配任何模式的情况,则可以编写自定义函数来捕获异常并返回None:

这段代码在字符串与所有模式都不匹配时会报错。如果有些情况下字符串不匹配任何模式,你可以编写一个自定义函数来捕获异常并返回 None。

import re
def findCat(x):
    try:
        return next(Dic[k] for k in Dic if re.search(k, x))
    except:
        return None

df['OUT'] = df.GO.map(findCat)
df

这差不多是我想的...但还远远不够。 - piRSquared
@piRSquared 显然,MaxU有更好的方法来解决这个问题。 - Psidom
我真的很惊讶 - 在以前的版本中,DF.replace()Series.str.replace() 总是比 Series.map() 慢 - 在 Pandas 0.19.2 中对于具有 30,000 行的 DF 的这种特殊情况不是这种情况! - MaxU - stand with Ukraine
1
可能是由于在map中使用了lambda表达式,它还会调用regex匹配,这可能会导致速度变慢。 - Psidom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接