【问题标题】:If a Pandas column doesn't contain a value from another column in the same row, then add the value from another column in a new line如果 Pandas 列不包含同一行中另一列的值,则将另一列中的值添加到新行中
【发布时间】:2019-05-13 05:44:25
【问题描述】:

我想在新行中将“A”列中的值添加到“B”列中,前提是“A”列中的相应值不包含在“B”列中。

我的数据框:

df

  A          B
  value1     value4
  value1
  value1     value4\nvalue1\n
  value2     value4\nvalue7\n
  value2     value4\n
  value3
  value3     value4\nvalue3\nvalue6
  value3     value2\nvalue1
  value3     value3\nvalue1\nvalue6

所以,我想要的数据框

df

  A          B
  value1     value4\nvalue1
  value1     value1
  value1     value4\nvalue1
  value2     value4\nvalue7\nvalue2
  value2     value4\nvalue2
  value3     value3
  value3     value4\nvalue3\nvalue6
  value3     value2\nvalue1\nvalue3
  value3     value3\nvalue1\nvalue6

此外,问题是有时在“B”列中的字符串末尾,存在 \n 有时不存在。

我尝试使用df.A.str.contains(df["A"]),但当contains() 有数据框列时它不起作用。我认为这样的事情可以工作:df.B.str.extract('(%s)' % '|'.join(df.A)),这仅适用于“B”列中存在的“A”列中的值 - 用于匹配,我不知道如何适应我的问题。

【问题讨论】:

  • 这是一个乱七八糟的问题。为了更好地帮助您,我们需要查看df.head(10).to_dict() 的输出。

标签: python pandas dataframe join contains


【解决方案1】:

创建一个带有列表理解的布尔掩码。用空字符串替换缺失值并使用Series.where:

mask = [a in b for a, b in zip(df['A'], df['B'].fillna(''))]
b = df['B'].str.replace(r'\\n$', '')
df['B'] = b.where(mask, b + '\\n' + df['A']).fillna(df['A'])
print (df)
        A                       B
0  value1          value4\nvalue1
1  value1                  value1
2  value1          value4\nvalue1
3  value2  value4\nvalue7\nvalue2
4  value2          value4\nvalue2
5  value3                  value3
6  value3  value4\nvalue3\nvalue6
7  value3  value2\nvalue1\nvalue3
8  value3  value3\nvalue1\nvalue6

【讨论】:

  • 感谢您提供此解决方案。但是添加到末尾已经包含 \n 的字符串存在问题,然后我有一个空行,我不想要那个。此外,在“B”列的第三行末尾有 \n,我不希望这样。
  • @jezrael-to 总结 - 我不需要 \n\n (两个新行),我只需要 \n (一个新行),并且字符串末尾没有 \n。其他一切都应如此。
  • @slobokv83 - 是的,这里不可能使用strip,因为它也替换n,所以需要str.replace$ 匹配最后一个值。检查编辑的答案。
  • @jezrael-它工作得很好,非常感谢你......但我想知道,为什么我总是必须写“\n”而不是你的“\\n”?如果我将您写入的两个“\\n”都更改为“\n”,那么它就可以工作了。
  • @slobokv83 - 我想我使用 Windows,所以需要通过 '\\' 转义 '\'
【解决方案2】:

我建议您为此使用df.apply。在里面你将能够使用lambda 来创建你的条件。同样,我使用strip() 从开头和结尾删除\n。请看下面的代码:

# Code to build the dataframe
import pandas as pd
d = {'A': ['value1', 'value1', 'value1', 'value2', 'value2', 'value3', 'value3', 'value3', 'value3'], 'B': ['value4', '', 'value4\nvalue1\n', 'value4\nvalue7\n', 'value4\n', '', 'value4\nvalue3\nvalue6', 'value2\nvalue1', 'value3\nvalue1\nvalue6']}
df = pd.DataFrame(data=d)

# Here is the code to use
print(df.apply(lambda x: [x["A"], (x["B"].strip()+"\n"+x["A"]).strip()] if x["A"] not in x["B"] else [x["A"], x["B"].strip()], axis=1, result_type='broadcast'))

输出:

        A                         B
0  value1            value4\nvalue1
1  value1                    value1
2  value1            value4\nvalue1
3  value2    value4\nvalue7\nvalue2
4  value2            value4\nvalue2
5  value3                    value3
6  value3    value4\nvalue3\nvalue6
7  value3    value2\nvalue1\nvalue3
8  value3    value3\nvalue1\nvalue6
8  value3    value3\nvalue1\nvalue6

【讨论】:

  • 感谢您的回答。我必须学习并经常在lambda函数中使用if语句,但我正在pandas中学习。
  • 啊哈,谢谢你,因为我问了超过 30 000 行。我必须切换,因为我有 fillna()、replace()...
  • @JonathanGagne - 不,你错了。应用是引擎盖下的循环,所以更慢。我检查了它 - df = pd.concat([df] * 1000, ignore_index=True) 9000 行。
  • @JonathanGagne - 并获得mask = [a in b for a, b in zip(df['A'], df['B'].fillna(''))] b = df['B'].str.replace(r'\\n$', '') df['B'] = b.where(mask, b + '\\n' + df['A']).fillna(df['A']) 13.2 ms ± 724 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) %%timeit (df.apply(lambda x: [x["A"], (x["B"].strip()+"\n"+x["A"]).strip()] if x["A"] not in x["B"] else [x["A"], x["B"].strip()], axis=1, result_type='broadcast')) 651 ms ± 11 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
  • 感谢@jezrael,您的解决方案很可靠。带有理解列表的布尔掩码,我喜欢它!
猜你喜欢
  • 1970-01-01
  • 2020-07-19
  • 2013-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-25
  • 2020-11-24
  • 2022-01-05
相关资源
最近更新 更多