Pandas - 检查列表列中的字符串列是不是按行排列

Posted

技术标签:

【中文标题】Pandas - 检查列表列中的字符串列是不是按行排列【英文标题】:Pandas - Check if column of strings in column of lists row wisePandas - 检查列表列中的字符串列是否按行排列 【发布时间】:2019-11-11 07:11:47 【问题描述】:

我有一个数据框,你可以用它来构建:

dflist=[['123',['abc','qw3','123']],
        ['ab12',['3e4r5','12we3','asd23','q2w3']]]
df=pd.DataFrame(dflist,columns=['check','checklist'])

看起来像这样:

  check                    checklist
0   123              [abc, qw3, 123]
1  ab12  [3e4r5, 12we3, asd23, q2w3]

我想检查“check”列中的项目是否在“checklist”列的列表中。所以我希望生成的数据框看起来像:

  check                    checklist checkisin
0   123              [abc, qw3, 123]      True
1  ab12  [3e4r5, 12we3, asd23, q2w3]     False

我尝试了几件事,包括以各种形式使用 .isin,包括 apply/lambda。并且直接。

这个:

df['checkisin']=df.check.isin(df.checklist)

产生:

  check                    checklist  checkisin
0   123              [abc, qw3, 123]      False
1  ab12  [3e4r5, 12we3, asd23, q2w3]      False

其中有两个 False。

试试这个: df['checkisin']=df.apply(lambda x:x.check.isin(x.checklist)) 给出这个错误:

AttributeError: ("'Series' object has no attribute 'check'", 'occurred at index check')

试试这个:

df['checkisin']=df.apply(lambda x:x['check'] in x.checklist)

给出这个错误:

KeyError: ('check', 'occurred at index check')

我确定我在这里遗漏了一些简单的东西。我知道我可以循环这个,但是寻找一个 Pandas Dataframe 列明智的解决方案,因为我拥有的 DF 非常大并且试图“最”有效地处理。

谢谢!

【问题讨论】:

【参考方案1】:

您有一列列表,当然,pandas 没有任何函数可以原生支持对结构如此糟糕的数据的操作。如果您想要最高性能,我建议您使用列表理解:

df['checkisin'] = [c in l for c, l in zip(df['check'], df['checklist'])]
df
  check                    checklist  checkisin
0   123              [abc, qw3, 123]       True
1  ab12  [3e4r5, 12we3, asd23, q2w3]      False

如果您担心 NaN 和类型不匹配,可以考虑实施 try-except 错误处理:

def check_isin(check, checklist):
    try:
        return check in checklist
    except TypeError:
        return np.NaN

df['checkisin'] = [
    check_isin(c, l) for c, l in zip(df['check'], df['checklist'])
]

Evidence suggests 列表推导是无法向量化操作的最理想选择。

PS,如果您打算进行大量成员资格测试,请考虑将您的列表列转换为集合列。


这是一个如何矢量化此操作的示例。

from itertools import chain

cl = df.pop('checklist')
df = (pd.DataFrame(df.reset_index().values.repeat(cl.str.len(), axis=0), 
                   columns=['group', *df.columns])
        .assign(checklist=list(chain.from_iterable(cl))))

df

   group check checklist
0      0   123       abc
1      0   123       qw3
2      0   123       123
3      1  ab12     3e4r5
4      1  ab12     12we3
5      1  ab12     asd23
6      1  ab12      q2w3
7      1  ab12       123

(df['check'] == df['checklist']).groupby(df.group).any()

group
0     True
1    False
dtype: bool

【讨论】:

列中有列表的用例很多。就我而言,列表可能很长,因此将每个项目放在自己的列中是行不通的。此外,列表可以是非常不同的大小。在这种情况下,您会建议如何构建数据?将每个列表都设为字符串并使用 .contains 会更好吗? @clg4 我认为这也行不通,因为您需要进行逐行比较(str.contains 不能这样做)。我已经根据我对如何构建数据以及如何使用 groupby 进行矢量化的建议来编辑我的答案。 PS,您将需要添加一个额外的列来识别组。见上文。 我在路上。当我回到实验室时,我会看看这些。敬请期待,谢谢 @clg4 如果你想分配回来,你应该使用transformdf['checkisin'] = (df['check'] == df['checklist']).groupby(df['group']).transform('any') 好的,一切正常。为 10,000 行 df 的所有答案添加了 timeits。回答 1)62.2u,2 带错误检查)84.2u,3 矢量化)1200u。所以对你来说,前两个看起来最好。谢谢,敬请期待获胜者。【参考方案2】:

我将使用isinSeries,isin 和Series 将首先匹配index,这与list 不同

pd.DataFrame(df.checklist.tolist(),index=df.index).isin(df.check).any(1)
Out[496]: 
0     True
1    False
dtype: bool

或者

pd.DataFrame(df.checklist.tolist(),index=df.index).eq(df.check,0).any(1)

【讨论】:

@cs95 我检查它是否与 eq 相同 ...所以应该可以工作 我不知道 df.isin 只检查行...直到! @cs95 仅在通过系列时:-) 有趣,从我的测试看来 eq 比 isin 稍快,但都比 list comps 稍慢。 @cs95 为真匹配后端的索引几乎等于for循环【参考方案3】:

map

df.assign(checkisin=[*map(lambda s, x: s in x, *map(df.get, df))])

  check                    checklist  checkisin
0   123              [abc, qw3, 123]       True
1  ab12  [3e4r5, 12we3, asd23, q2w3]      False

如果你的数据框有更多的列,你可以更明确

cols = ['check', 'checklist']
df.assign(checkisin=[*map(lambda s, x: s in x, *map(df.get, cols))])

【讨论】:

timeit of 146u 这么慢但有效!投票但必须让@cs95 获胜。谢谢。 但我赢在风格,对吧?!告诉我我以风格取胜,否则我的自尊心受不了。如果不是因为@cs95 /drats 的干预,我也会赢得速度比赛【参考方案4】:

你可以试试:

df['checkisin'] = [v in df.checklist[i] for i, v in enumerate(df.check)]

或:

df['checkisin'] = [i in j for i, j in zip(df.check, df.checklist)]

或:

df['checkisin'] = list(map(lambda i, j: i in j, df.check, df.checklist))

或者(如果你喜欢df.assign):

df.assign(checkisin=[*map(lambda i, j: i in j, df.check, df.checklist)])

结果:

  check                    checklist  checkisin
0   123              [abc, qw3, 123]       True
1  ab12  [3e4r5, 12we3, asd23, q2w3]      False

【讨论】:

为您在 10000 行数据帧上的选项添加了时间。所有选项都有效。 1 次枚举)628u,2 zip)125u,3 地图)93.4u 4 分配)238u。所有的工作,但都比@cs95 更多的时间。所以点赞和感谢,但 cs95 是赢家……

以上是关于Pandas - 检查列表列中的字符串列是不是按行排列的主要内容,如果未能解决你的问题,请参考以下文章

从pandas DataFrame中另一列中的位置给定的字符串列中提取字符[重复]

需要使用 pandas.str() 使用字符串列表从列中选择值 [重复]

如何检查一系列字符串是不是包含在 PANDAS DataFrame 列中并将该字符串分配为行中的新列?

检查列表中的单词并在 pandas 数据框列中删除这些单词

从 pandas DataFrame 中的多个字符串列中删除子字符串

Pandas 按行中的值和其他列中的值在行之间进行差异