python - 根据每个句子的第一个单词将 Pandas 数据框列中的字符串列表分解为新列

标签 python regex pandas

所以我有大约 40,000 行人和他们的投诉。我试图将它们分类到各自的列中进行分析,并供其他分析师使用 在我公司,使用其他工具的人可以使用这些数据。

DataFrame 示例:

df = pd.DataFrame({"person": [1, 2, 3], 
                   "problems": ["body: knee hurts(bad-pain), toes hurt(BIG/MIDDLE); mind: stressed, tired", 
                                "soul: missing; mind: can't think; body: feels great(lifts weights), overweight(always bulking), missing a finger", 
                                "none"]})
df     
╔═══╦════════╦══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
║   ║ person ║                                                     problems                                                     ║
╠═══╬════════╬══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣
║ 0 ║      1 ║ body: knee hurts(bad-pain), toes hurt(BIG/MIDDLE); mind: stressed, tired                                         ║
║ 1 ║      2 ║ soul: missing; mind: can't think; body: feels great(lifts weights), overweight(always bulking), missing a finger ║
║ 2 ║      3 ║ none                                                                                                             ║
╚═══╩════════╩══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝

期望的输出:

╔═══╦════════╦══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╦════════════════════════════════════════════════════════════════════════════════╦═══════════════════════╦═══════════════╗
║   ║ person ║                                                     problems                                                     ║                                      body                                      ║         mind          ║     soul      ║
╠═══╬════════╬══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╬════════════════════════════════════════════════════════════════════════════════╬═══════════════════════╬═══════════════╣
║ 0 ║      1 ║ body: knee hurts(bad-pain), toes hurt(BIG/MIDDLE); mind: stressed, tired                                         ║ body: knee hurts(bad-pain), toes hurt(BIG/MIDDLE)                              ║ mind: stressed, tired ║ NaN           ║
║ 1 ║      2 ║ soul: missing; mind: can't think; body: feels great(lifts weights), overweight(always bulking), missing a finger ║ body: feels great(lifts weights), overweight(always bulking), missing a finger ║ mind: can't think     ║ soul: missing ║
║ 2 ║      3 ║ none                                                                                                             ║ NaN                                                                            ║ NaN                   ║ NaN           ║
╚═══╩════════╩══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╩════════════════════════════════════════════════════════════════════════════════╩═══════════════════════╩═══════════════╝

我尝试过的事情/我在的地方:

因此,我至少能够使用似乎可以处理我的真实数据的正则表达式语句将它们分开。

df.problems.str.extractall(r"(\b(?!(?: \b))[\w\s.()',:/-]+)")


+---+-------+--------------------------------------------------------------------------------+
|   |       |                                       0                                        |
+---+-------+--------------------------------------------------------------------------------+
|   | match |                                                                                |
| 0 | 0     | body: knee hurts(bad-pain), toes hurt(BIG/MIDDLE)                              |
|   | 1     | mind: stressed, tired                                                          |
| 1 | 0     | soul: missing                                                                  |
|   | 1     | mind: can't think                                                              |
|   | 2     | body: feels great(lifts weights), overweight(always bulking), missing a finger |
| 2 | 0     | none                                                                           |
+---+-------+--------------------------------------------------------------------------------+

我是正则表达式的初学者,所以我希望这可以做得更好。我原来的正则表达式模式是 r'([^;]+)',但我试图排除分号后的空格。

所以我很茫然。我玩过:

df.problems.str.extractall(r"(\b(?!(?:\b))[\w\s.()',:/-]+)").unstack( ),它在我这里的示例中“有效”(不会出错)。

但是对于我的真实数据,我得到一个错误:"ValueError: Index contains duplicate entries, cannot reshape"

即使它适用于我的真实数据,我仍然必须弄清楚如何将这些“类别”( body 、思想、灵魂)放入指定的列中。

如果我能更好地表达这个问题,我可能会更幸运。我正在努力真正地自学,所以我会很感激任何线索,即使它们不是完整的解决方案。

我正在寻找一条线索,也许我可以通过 groupby 或 multiIndex 诀窍以某种方式做到这一点。对编程有点陌生,所以我仍然在黑暗中摸索。我将不胜感激任何人必须提供的任何提示或想法。谢谢!

编辑:我只想回来并提及我在使用@WeNYoBen 的解决方案时在真实数据中遇到的错误“ValueError:索引包含重复条目,无法 reshape ”:

(df.problems.str.extractall(r"(\b(?!(?: \b))[\w\s.()',:/-]+)")[0]
.str.split(':',expand=True)
.set_index(0,append=True)[1]
.unstack()
.groupby(level=0)
.first())

原来我有一些组有多个冒号。例如:

df = pd.DataFrame({"person": [1, 2, 3], 
                   "problems": ["body: knee hurts(bad-pain), toes hurt(BIG/MIDDLE); mind: stressed, energy: tired", 
                                "soul: missing; mind: can't think; body: feels great(lifts weights), overweight(always bulking), missing a finger", 
                                "none"]})




╔═══╦════════╦══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
║   ║ person ║                                                     problems                                                     ║
╠═══╬════════╬══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣
║ 0 ║      1 ║ body: knee hurts(bad-pain), toes hurt(BIG/MIDDLE); mind: stressed, energy: tired                                 ║
║ 1 ║      2 ║ soul: missing; mind: can't think; body: feels great(lifts weights), overweight(always bulking), missing a finger ║
║ 2 ║      3 ║ none                                                                                                             ║
╚═══╩════════╩══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝

查看反射(reflect)我发现的边缘情况的第一行更新 ;头脑:压力大,精力:疲倦

我能够通过改变我的正则表达式来解决这个问题,说明匹配的开头必须是字符串的开头或者前面有一个分号。

splits = [r'(^)(.+?)[:]', r'(;)(.+?)[:]']
str.split('|'.join(splits)

在那之后,我只需要重新调整 set_index 部分就可以让@WeNYoBen 的有用解决方案起作用,所以我会坚持使用这个。

最佳答案

它并不优雅,但它完成了工作:

df['split'] = df.problems.str.split(';')
df['mind'] = df.split.apply(
    lambda x: ''.join([category for category in x if 'mind' in category]))
df['body'] = df.split.apply(
    lambda x: ''.join([category for category in x if 'body' in category]))
df['soul'] = df.split.apply(
    lambda x: ''.join([category for category in x if 'soul' in category]))
df.drop('split', inplace=True)

你可能会换行

df[cat] = df.split.apply(lambda x: ''.join([category for category in x if cat in category])) 

在一个函数中,并在您的数据帧上为每只 cat 运行它(例如 cats=['mind', 'body', 'soul', 'whathaveyou', 'etc.' ]


编辑:

正如@ifly6 所指出的,用户输入的字符串中可能存在关键字交集。为了安全起见,应该将函数更改为

df[cat] = df.split.apply(lambda x: ''.join([category for category in x if category.startswith(cat)])) 

关于python - 根据每个句子的第一个单词将 Pandas 数据框列中的字符串列表分解为新列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57435869/

相关文章:

python - 如何比较两个列表并获取匹配项的所有索引

python - 在 Python 中从 URL 中抓取特定信息

Javascript Regex 将 $.param 返回的 url 字符串强制转换为 MVC 模型绑定(bind)约定

python - 有效地将 DataFrame 列转换为对象

python - 对象类型列,百分比以 % 和小数显示,全部转换为小数

python - fillna(0) 仅适用于特定列,而不命名每个列

python - python为什么显示 'list index out of range'错误?

python - 如何在 Django JSONField 中过滤 JSON 数组

java - 最后一个有效括号之间的文本的正则表达式

javascript - 如何在可编辑 div 中替换给定的 "starting index"和 "string to replace"字符串