V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
badacook
V2EX  ›  Python

DataFrame 内容处理

  •  
  •   badacook · 251 天前 · 1272 次点击
    这是一个创建于 251 天前的主题,其中的信息可能已经有所发展或是发生改变。
    想对 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
    17 条回复    2021-03-29 19:18:25 +08:00
    HelloViper
        1
    HelloViper  
       251 天前
    axis=1,横向 apply,每个切片是一个 series,直接遍历了正则提取最后 join 就可以了
    badacook
        2
    badacook  
    OP
       251 天前
    @HelloViper 我说了要保持 DataFrame layout,那 不包含括号的,这个 python 里的 if 返回值为 bool 值的 判断条件 我写不出来,还有就是 我想看看 有没有简便的方法
    reself
        3
    reself  
       251 天前
    mapper = lambda x: ''.join(re.findall(r, x)) or x
    df_new = df.applymap(mapper)
    reself
        4
    reself  
       251 天前
    @reself 前提是括号中有值。括号内是空的话就不行了,mapper 改一下就行。
    reself
        5
    reself  
       251 天前
    @reself 对了,r 就是 re.compile(r'[(](.*?)[)]', re.S)
    Gatsbywl
        6
    Gatsbywl  
       251 天前
    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
        7
    badacook  
    OP
       251 天前
    @reself 非常感谢 你的指点,这里面 lambda 'or' 咋这么厉害,居然实现了一个 if 分支的 else 输出,太感谢了
    badacook
        8
    badacook  
    OP
       251 天前
    @Gatsbywl 非常感谢你的细致指点,这边测试 ok 正试着理解一下 复合表达式 致敬!
    HelloViper
        9
    HelloViper  
       251 天前
    @badacook or 是取第一个有值的,这样比较优雅;也可以 lambda x: ''.join(re.findall(r, x)) if re.findall(r, x) else x;
    另外好像 str 列内置了正则,Series.str.findall
    imn1
        10
    imn1  
       251 天前
    不需要 lambda,pandas 的 str.replace 支持正则的,而且是跟 re 模块相同语法
    badacook
        11
    badacook  
    OP
       251 天前
    @imn1 我最先看的就是 str.replace,但这个 既不是全部替,也不是部分替换,是 若含有(),保留()内部内容,这个 replace,我写不出来,而且 想在 df.applymap 类似函数体内完成,判断就寄 希望与 lambda 的判断分支了
    badacook
        12
    badacook  
    OP
       250 天前
    @HelloViper 还有一点 使用最后的 df.applymap() 条件处理时,需要先将 DataFrame 中非字符数据列 全部转换成 字符处理,df = df.applymap(str),这个好像 也只能是这样了,有点儿失真
    imn1
        13
    imn1  
       250 天前
    @badacook #11
    只能说你的正则没写对,replace 本来就是匹配才替换,不匹配不替换的
    "abc".replace("aaa", ""),你觉得结果会是空字串么?

    如果你测试得到了全部都替换了的结果,就是正则匹配写错了
    DataFrame.replace(to_replace=匹配的正则, value=替换的正则, regex=True)
    badacook
        14
    badacook  
    OP
       250 天前
    @imn1 这不是 写不出这个正则嘛 字符串,含有()就保留()里面的内容,要是写得出这个正则, 我也提前看过了 那个 replace 函数了 也不会在这里请教大家了
    imn1
        15
    imn1  
       250 天前
    @badacook #14
    那你问题问错了,实际就是求个正则
    r'[^()]*\(([^()]+)\)[^()]*'
    r'\1'
    自己测试一下吧
    badacook
        16
    badacook  
    OP
       250 天前
    @imn1 猛男啊 虽然我也学过正则,那仅仅是知道,难怪我开始都怀疑 正则能不能实现,非常感谢,致敬
    badacook
        17
    badacook  
    OP
       250 天前
    @HelloViper
    @reself
    @Gatsbywl
    imn1 大神用一行正则 直接实现了,df = df.replace(r'[^()]*\(([^()]+)\)[^()]*', value=r'\1', regex=True)
    包含括号,就将内容替换为括号里面的内容,太厉害了
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2300 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 08:35 · PVG 16:35 · LAX 00:35 · JFK 03:35
    ♥ Do have faith in what you're doing.