DataFrame 内容处理

2021-03-29 11:29:27 +08:00
 badacook
想对 DataFrame 二维表内包含括号的数据进行处理
具体是 包含()的元素,只保留()内的内容,不包含的不作处理
df = pd.DataFrame([["x(a)","(ab)","c","d"],["a","2b","2x(3c)y","d"],["a","b","c","4(d)e"]])
0 1 2 3
0 x(a) (ab) c d
1 a 2b 2x(3c)y d
2 a b c 4(d)e
其中含括号的值 只保留括号里面的内容,不含括号的不作处理
如第一行处理后 :a ab c d
已找到如下 正则表达式匹配方式
p1 = re.compile(r'[(](.*?)[)]', re.S)
print(''.join(re.findall(p1, '2x(3c)y')))
3c
参照 stackoverflow 上的这篇 DataFrame 替换字符串的帖子
https://stackoverflow.com/questions/48214863/python-replace-whole-values-in-dataframe-string-and-not-substrings

想使用 df.apply 方法,结合 lambda 表达式 完成元素内容的正则判断,如果含括号就 replace ()里面的内容,不含就不做更改,保持 DataFrame layout
尝试了 写不出,不知道有没有朋友,能帮忙写一下 判断字符串是否包含()并实现这个条件替换,或者有其他思路 处理 DataFrame
2283 次点击
所在节点    Python
17 条回复
HelloViper
2021-03-29 12:14:21 +08:00
axis=1,横向 apply,每个切片是一个 series,直接遍历了正则提取最后 join 就可以了
badacook
2021-03-29 12:23:09 +08:00
@HelloViper 我说了要保持 DataFrame layout,那 不包含括号的,这个 python 里的 if 返回值为 bool 值的 判断条件 我写不出来,还有就是 我想看看 有没有简便的方法
reself
2021-03-29 13:22:27 +08:00
mapper = lambda x: ''.join(re.findall(r, x)) or x
df_new = df.applymap(mapper)
reself
2021-03-29 13:23:56 +08:00
@reself 前提是括号中有值。括号内是空的话就不行了,mapper 改一下就行。
reself
2021-03-29 13:24:45 +08:00
@reself 对了,r 就是 re.compile(r'[(](.*?)[)]', re.S)
Gatsbywl
2021-03-29 13:33:03 +08:00
def getString(s):
pattern = r'[(](.*?)[)]'
reString = re.compile(pattern, re.S)
tmpString = re.findall(reString, s)
return tmpString[0] if tmpString else s
df.applymap(getString)
===================================
或者一行,易读性不好:
df.applymap(lambda s:re.findall(re.compile(r'[(](.*?)[)]', re.S), s)[0] if re.findall(re.compile(r'[(](.*?)[)]', re.S), s) else s)
badacook
2021-03-29 15:08:11 +08:00
@reself 非常感谢 你的指点,这里面 lambda 'or' 咋这么厉害,居然实现了一个 if 分支的 else 输出,太感谢了
badacook
2021-03-29 15:13:59 +08:00
@Gatsbywl 非常感谢你的细致指点,这边测试 ok 正试着理解一下 复合表达式 致敬!
HelloViper
2021-03-29 15:14:27 +08:00
@badacook or 是取第一个有值的,这样比较优雅;也可以 lambda x: ''.join(re.findall(r, x)) if re.findall(r, x) else x;
另外好像 str 列内置了正则,Series.str.findall
imn1
2021-03-29 15:23:14 +08:00
不需要 lambda,pandas 的 str.replace 支持正则的,而且是跟 re 模块相同语法
badacook
2021-03-29 16:32:15 +08:00
@imn1 我最先看的就是 str.replace,但这个 既不是全部替,也不是部分替换,是 若含有(),保留()内部内容,这个 replace,我写不出来,而且 想在 df.applymap 类似函数体内完成,判断就寄 希望与 lambda 的判断分支了
badacook
2021-03-29 16:45:55 +08:00
@HelloViper 还有一点 使用最后的 df.applymap() 条件处理时,需要先将 DataFrame 中非字符数据列 全部转换成 字符处理,df = df.applymap(str),这个好像 也只能是这样了,有点儿失真
imn1
2021-03-29 17:05:17 +08:00
@badacook #11
只能说你的正则没写对,replace 本来就是匹配才替换,不匹配不替换的
"abc".replace("aaa", ""),你觉得结果会是空字串么?

如果你测试得到了全部都替换了的结果,就是正则匹配写错了
DataFrame.replace(to_replace=匹配的正则, value=替换的正则, regex=True)
badacook
2021-03-29 17:19:56 +08:00
@imn1 这不是 写不出这个正则嘛 字符串,含有()就保留()里面的内容,要是写得出这个正则, 我也提前看过了 那个 replace 函数了 也不会在这里请教大家了
imn1
2021-03-29 17:32:24 +08:00
@badacook #14
那你问题问错了,实际就是求个正则
r'[^()]*\(([^()]+)\)[^()]*'
r'\1'
自己测试一下吧
badacook
2021-03-29 19:12:25 +08:00
@imn1 猛男啊 虽然我也学过正则,那仅仅是知道,难怪我开始都怀疑 正则能不能实现,非常感谢,致敬
badacook
2021-03-29 19:18:25 +08:00
@HelloViper
@reself
@Gatsbywl
imn1 大神用一行正则 直接实现了,df = df.replace(r'[^()]*\(([^()]+)\)[^()]*', value=r'\1', regex=True)
包含括号,就将内容替换为括号里面的内容,太厉害了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/766094

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX