【问题标题】: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]

感谢您的帮助!

【问题讨论】:

    标签: python pandas where list-comprehension apply


    【解决方案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 一秒,让我再提供一个
      • 尝试了矢量化选项,它实际上比我的数据集上的其他选项慢得多...
      猜你喜欢
      • 2019-02-22
      • 2020-04-22
      • 2022-12-12
      • 2013-08-01
      • 2019-10-03
      • 2022-01-09
      • 2020-09-07
      相关资源
      最近更新 更多