【问题标题】:Pandas Python : Col[C] if value is in Col[A] and Col[B]Pandas Python:如果值在 Col[A] 和 Col[B] 中,则为 Col[C]
【发布时间】:2019-06-19 08:24:00
【问题描述】:

我有一个这样的数据框:

    ColA             ColB                        ColC
"lorem ipsum"     ["lorem", "foo", "bar"]
"lorem ipsum"      NaN
NaN                ["lorem", "foo", "bar"]
NaN                 NaN

我正在尝试得到这个输出:

    ColA             ColB                        ColC
"lorem ipsum"     ["lorem", "foo", "bar"]       "lorem"

我尝试使用这样的理解列表:

df["C"] = [elem for elem in df["B"] if elem in df["A"] ]

但没有成功:

TypeError: unhashable type: 'list' 如果我将我的 ColB 格式化为列表,并且, ValueError: Length of values does not match length of index 如果我使用元组

我们将不胜感激, 谢谢。

Edit + Edit 2:两列中只有一个单词(或无),我需要抓住它以将其放在 C 列中。 我也忘了提到 ColA 和 ColB 可以有 NaN 作为值。

【问题讨论】:

  • 您是否只想要 一个 相交的单词(如果是,如果有多个,您想做什么)?或者你想要一个单词列表?
  • 两列中只有一个词,我将编辑我的问题更明确
  • 先检查ColB是String还是list?

标签: python python-3.x string pandas


【解决方案1】:

您可以定义自定义函数,然后使用map

# data adapted from @jezrael
df = pd.DataFrame({'A':['lorem ipsum', 'lorem ipsum', np.nan, np.nan, 'test string'],
                   'B':[["lorem", "foo", "bar"], np.nan, ["lorem", "foo", "bar"], np.nan, ["no", "match"]]})

def tester(val1, val2):
    if (val1 != val1) or (val2 != val2):
        return ''
    return next((x for x in val2 if x in val1), '')

df['C'] = list(map(tester, df['A'], df['B']))

'' 的默认参数确保您在没有匹配项的地方有一个空字符串。我们还利用np.nan != np.nan这一事实。

结果:

print(df)

             A                  B      C
0  lorem ipsum  [lorem, foo, bar]  lorem
1  lorem ipsum                NaN       
2          NaN  [lorem, foo, bar]       
3          NaN                NaN       
4  test string        [no, match]       

【讨论】:

  • 查看我的回答下的评论。
  • 我仍然得到 TypeError: 'float' object is not iterable 我忘了提到 ColA 或 ColB 的某些元素可能是 NaN,我将它添加到我的问题中。
  • 很高兴我能从你那里学到新东西,谢谢!加1
【解决方案2】:

在我用 fillna 替换每个 NaN 之后,以前的解决方案就像一个魅力。

df = df.fillna("undefined")
df["C"] = [next((y for y in b if y in a), '') for a, b, in zip(df["A"],df["B"])]

谢谢

【讨论】:

  • 我测试了你的样本数据,它在这个解决方案中运行不佳,你确定它运行良好吗?
  • 通过输出样本数据检查我的答案。
【解决方案3】:

通过try+except 使用自定义函数并通过pipe 传递DataFrame:

df = pd.DataFrame({'A':['lorem ipsum','lorem ipsum',np.nan, np.nan],
                   'B':[["lorem", "foo", "bar"], np.nan, ["lorem", "foo", "bar"], np.nan]})
print (df)
             A                  B
0  lorem ipsum  [lorem, foo, bar]
1  lorem ipsum                NaN
2          NaN  [lorem, foo, bar]
3          NaN                NaN

def test(df):
    out = []
    for a, b in zip(df["A"], df["B"]):
        try:
            out.append(next(y for y in b if y in a))
        except Exception:
            out.append('')
    return out

df["C"] = df.pipe(test)
print (df)
             A                  B      C
0  lorem ipsum  [lorem, foo, bar]  lorem
1  lorem ipsum                NaN       
2          NaN  [lorem, foo, bar]       
3          NaN                NaN       

另一个效果不佳的解决方案:

df = df.fillna("undefined")
df["C"] = [next((y for y in b if y in a), '') for a, b, in zip(df["A"],df["B"])]
print (df)


             A                  B  C
0  lorem ipsum      [d, foo, bar]   
1  lorem ipsum          undefined  u
2    undefined  [lorem, foo, bar]   
3    undefined          undefined  u

【讨论】:

  • 我喜欢这个主意,但 IMO map 在循环中比 list.append 效果更好 :)
【解决方案4】:

没有尝试和解决方案,它适用于一个词!

df = pd.DataFrame({'colA':['lorem ipsum','lorem ipsum',None,None],
                   'colB':[["lorem", "foo", "bar"],None,["lorem", "foo", "bar"],None]})

df.loc[:,'colC'] = df.apply(lambda x: ''.join([w for w in x.colA.split() \
                             if w in x.colB]) if all(x) else '',axis=1 )

    colA    colB    colC
0   lorem ipsum [lorem, foo, bar]   lorem
1   lorem ipsum None    None
2   None    [lorem, foo, bar]   None
3   NaN None    None

【讨论】:

  • 也期望输出是空字符串,而不是 None
  • 感谢您帮助我学习。你能提到失败的例子吗?
  • 当然,[lorem ipsum, foo, bar]
  • 所以只在一个单词测试的答案中提及就可以了;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-11
  • 2015-06-23
  • 1970-01-01
  • 2016-07-19
  • 1970-01-01
  • 1970-01-01
  • 2020-06-14
相关资源
最近更新 更多