Pandas Dataframe 检查列值是不是在列列表中

Posted

技术标签:

【中文标题】Pandas Dataframe 检查列值是不是在列列表中【英文标题】:Pandas Dataframe Check if column value is in column listPandas Dataframe 检查列值是否在列列表中 【发布时间】:2018-05-10 20:06:29 【问题描述】:

我有一个数据框df

data = 'id':[12,112],
        'idlist':[[1,5,7,12,112],[5,7,12,111,113]]
       
df=pd.DataFrame.from_dict(data)

看起来像这样:

    id                idlist
0   12    [1, 5, 7, 12, 112]
1  112  [5, 7, 12, 111, 113]

我需要检查id 是否在idlist 中,然后选择或标记它。我尝试了以下变体并收到注释错误:

df=df.loc[df.id.isin(df.idlist),:] #TypeError: unhashable type: 'list'
df['flag']=df.where(df.idlist.isin(df.idlist),1,0) #TypeError: unhashable type: 'list'

解决方案的其他一些可能方法是列表理解中的.apply

我在这里寻找一种解决方案,它要么选择id 位于idlist 中的行,要么将id 位于idlist 中的行标记为1。生成的df 应该是:

   id              idlist
0  12  [1, 5, 7, 12, 112]

或:

   flag   id                idlist
0     1   12    [1, 5, 7, 12, 112]
1     0  112  [5, 7, 12, 111, 113]

感谢您的帮助!

【问题讨论】:

【参考方案1】:

使用apply:

df['flag'] = df.apply(lambda x: int(x['id'] in x['idlist']), axis=1)
print (df)
    id                idlist  flag
0   12    [1, 5, 7, 12, 112]     1
1  112  [5, 7, 12, 111, 113]     0

类似的:

df['flag'] = df.apply(lambda x: x['id'] in x['idlist'], axis=1).astype(int)
print (df)
    id                idlist  flag
0   12    [1, 5, 7, 12, 112]     1
1  112  [5, 7, 12, 111, 113]     0

list comprehension:

df['flag'] = [int(x[0] in x[1]) for x in df[['id', 'idlist']].values.tolist()]
print (df)
    id                idlist  flag
0   12    [1, 5, 7, 12, 112]     1
1  112  [5, 7, 12, 111, 113]     0

过滤解决方案:

df = df[df.apply(lambda x: x['id'] in x['idlist'], axis=1)]
print (df)
   id              idlist
0  12  [1, 5, 7, 12, 112]

df = df[[x[0] in x[1] for x in df[['id', 'idlist']].values.tolist()]]
print (df)

   id              idlist
0  12  [1, 5, 7, 12, 112]

【讨论】:

我的 df 1.6m 行的时间: 我认为列表理解解决方案应该更快。 这里是:我的 1.6m 行 df 上的时间:df['flag'] = df.loc[:, ('id', 'idlist')].apply(lambda x: 1 if x[0] in x[1] else 0, axis=1) 2min10s | df['flag'] = df.apply(lambda x: int(x['id'] in x['idlist']), axis=1) 1min55s | df['flag'] = df.apply(lambda x: x['id'] in x['idlist'], axis=1).astype(int) 1min54s | df['flag'] = [int(x[0] in x[1]) for x in df[['id', 'idlist']].values.tolist()] 1min24s | df.apply(lambda x : set([x.id]).issubset(x.idlist),1).astype(int)。下面和删除的各种循环要慢得多。获胜者是来自@jezreal 的列表理解版本! 获胜者是基于我的时间的列表理解【参考方案2】:

您可以使用df.apply 并处理每一行并创建一个新的列标志,该标志将检查条件并根据请求的第二个输出为您提供结果。

df['flag'] = df.loc[:, ('id', 'idlist')].apply(lambda x: 1 if x[0] in x[1] else 0, axis=1)

print(df)

x[0] is idx[1] is idlist 的位置

【讨论】:

你可以只使用列名进行索引,所以:df['flag'] = df.apply(lambda x: x.id in x.idlist, axis=1) @Swier - 这是我的回答;) @jezrael dammit,你打败了我:P【参考方案3】:

尝试简单的for循环:

flaglist = []
for i in range(len(df)):
    if df.id[i] in df.idlist[i]:
        flaglist.append(1)
    else:
        flaglist.append(0)
df["flag"] = flaglist 

df:

    id                idlist  flag
0   12    [1, 5, 7, 12, 112]     1
1  112  [5, 7, 12, 111, 113]     0

要删除行:

flaglist = []
for i in range(len(df)):
    if df.id[i] not in df.idlist[i]:
        flaglist.append(i)
df = df.drop(flaglist)

df:

   id              idlist  flag
0  12  [1, 5, 7, 12, 112]     1

以上可以转换为列表推导式来创建标志列:

df["flag"] = [df.id[i] in df.idlist[i]    for i in range(len(df))]
print(df)
#     id                idlist   flag
# 0   12    [1, 5, 7, 12, 112]   True
# 1  112  [5, 7, 12, 111, 113]  False

df["flag"] = [1 if df.id[i] in df.idlist[i] else 0    for i in range(len(df))]
print(df)
#     id                idlist  flag
# 0   12    [1, 5, 7, 12, 112]     1
# 1  112  [5, 7, 12, 111, 113]     0

用于选择行:

flaglist = [i   for i in range(len(df))   if df.id[i] in df.idlist[i]]
print(df.iloc[flaglist])
#    id              idlist
# 0  12  [1, 5, 7, 12, 112]

【讨论】:

【参考方案4】:

通过使用issubset

df.apply(lambda  x : set([x.id]).issubset(x.idlist),1).astype(int)
Out[378]: 
0    1
1    0
dtype: int32

通过使用np.vectorize

def myfun(x,y):
    return np.in1d(x,y)


np.vectorize(myfun)(df.id,df.idlist).astype(int)

时间:

%timeit np.vectorize(myfun)(df.id,df.idlist).astype(int)
10000 loops, best of 3: 92.3 µs per loop
%timeit df.apply(lambda  x : set([x.id]).issubset(x.idlist),1).astype(int)
1000 loops, best of 3: 353 µs per loop

【讨论】:

@clg4 一秒,让我再提供一个 尝试了矢量化选项,它实际上比我的数据集上的其他选项慢得多...

以上是关于Pandas Dataframe 检查列值是不是在列列表中的主要内容,如果未能解决你的问题,请参考以下文章

根据列值对带有 MultiIndex 的 pandas DataFrame 进行排序

根据列值删除Python Pandas中的DataFrame行[重复]

Pandas Dataframe 根据列值将值展平到单元格

使用 Pandas DataFrame 将列表等列值转换为多行

将列添加到包含其他列值列表的 pandas DataFrame

Pandas Dataframe Multiindex 按级别和列值排序