代码之家  ›  专栏  ›  技术社区  ›  Steven

按从组外收集值列表

  •  1
  • Steven  · 技术社区  · 5 年前

    我有一个数据框:

    df 
    
       ID  Value
    0   1   0.33
    1   1   0.91
    2   1   0.28
    3   2   0.36
    4   2   0.50
    5   3   0.47
    6   3   0.98
    7   3   0.34
    8   3   0.37
    

    我想 分组 ID并创建两个新列:

    1. “values_in”是ID的值列列表
    2. “values_out”是其他ID的值列列表

    输出如下:

    
       ID                 values_in                                  values_out
    0   1        [0.33, 0.91, 0.28]         [0.36, 0.5, 0.47, 0.98, 0.34, 0.37]
    1   2               [0.36, 0.5]  [0.33, 0.91, 0.28, 0.47, 0.98, 0.34, 0.37]
    2   3  [0.47, 0.98, 0.34, 0.37]               [0.33, 0.91, 0.28, 0.36, 0.5]
    

    如果我使用经典,我怎么能做到这一点 groupby 我会自动排除 values_out ?

    仅供参考:我不在乎列表中的顺序。

    0 回复  |  直到 5 年前
        1
  •  4
  •   Chris    5 年前

    单向使用 matmul :

    new_df = df.groupby("ID")["Value"].apply(list).reset_index(name="values_in")
    new_df["values_out"] = new_df["values_in"] @ (1 - np.eye(new_df.shape[0], dtype=int))
    print(new_df)
    

    输出:

       ID                 values_in                                  values_out
    0   1        [0.33, 0.91, 0.28]         [0.36, 0.5, 0.47, 0.98, 0.34, 0.37]
    1   2               [0.36, 0.5]  [0.33, 0.91, 0.28, 0.47, 0.98, 0.34, 0.37]
    2   3  [0.47, 0.98, 0.34, 0.37]               [0.33, 0.91, 0.28, 0.36, 0.5]
    
        2
  •  2
  •   Shubham Sharma mkln    5 年前

    使用 groupby 在…上 ID 并在列表中创建带有相应键的字典,如下所示: 身份证件 , values_in values_out 对于每个分组帧:

    d = [{'ID': k,
          'values_in': g['Value'].values,
          'values_out': df.loc[df['ID'].ne(k), 'Value'].values}
         for k, g in df.groupby('ID')]
    df_ = pd.DataFrame(d)
    

    结果:

       ID                 values_in                                  values_out
    0   1        [0.33, 0.91, 0.28]         [0.36, 0.5, 0.47, 0.98, 0.34, 0.37]
    1   2               [0.36, 0.5]  [0.33, 0.91, 0.28, 0.47, 0.98, 0.34, 0.37]
    2   3  [0.47, 0.98, 0.34, 0.37]               [0.33, 0.91, 0.28, 0.36, 0.5]
    

    计时(使用包含100个唯一 身份证件 ):

    df = pd.DataFrame({'ID': np.arange(100).tolist() * 100, 'Value': np.random.randn(10000)})
    df.shape
    (10000, 2)
    
    %%timeit -n10
    d = [{'ID': k,
          'values_in': g['Value'].values,
          'values_out': df.loc[df['ID'].ne(k), 'Value'].values}
         for k, g in df.groupby('ID')]
    df_ = pd.DataFrame(d)
    71.5 ms ± 4.19 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
    %%timeit -n10
    new_df = df.groupby("ID")["Value"].apply(list).reset_index(name="values_in")
    new_df["values_out"] = new_df["values_in"] @ (1 - np.eye(new_df.shape[0], dtype=int))
    204 ms ± 2.08 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
        3
  •  1
  •   jezrael    5 年前

    我在同一场景中使用了另一个例子来演示如何做到这一点:

    ids=[1,1,2,2,2,3]
    values=[12,13,14,15,12,12]
    df = pd.DataFrame({'Id':ids,'values':values})
    df
    

    输出:

        Id  values
    0   1       12
    1   1       13
    2   2       14
    3   2       15
    4   2       12
    5   3       12
    

    现在,你可以去拿 价值观 价值观 另外,正如我所做的:

    df2 = pd.DataFrame()
    for i in df["Id"].unique(): # Iterate through unique values of Ids
        in_list = list(df.loc[df['Id']==i, 'values']) # values_in
        out_list = list(df.loc[df['Id']!=i, 'values'])  #values_out
        df2 = df2.append([[i,in_list,out_list]]) #append each records
    df2.columns = ["ID","Values_in","Values_out"] #rename columns
    

    输出:

        ID      Values_in            Values_out
    0   1        [12, 13]      [14, 15, 12, 12]
    0   2    [14, 15, 12]          [12, 13, 12]
    0   3            [12]  [12, 13, 14, 15, 12]
    

    如果不想重复值,可以使用set而不是list来表示值\u in和值\u out

        4
  •  0
  •   jezrael    5 年前

    使用自定义函数和筛选依据 ID 价值观 boolean indexing :

    def f(x):
      return {'values_in': list(x), 'values_out': list(df.loc[df['ID'] != x.name, 'Value'])}
    
    
    df = df.groupby('ID')['Value'].apply(f).unstack()
    print (df)
                       values_in                                  values_out
    ID                                                                      
    1         [0.33, 0.91, 0.28]         [0.36, 0.5, 0.47, 0.98, 0.34, 0.37]
    2                [0.36, 0.5]  [0.33, 0.91, 0.28, 0.47, 0.98, 0.34, 0.37]
    3   [0.47, 0.98, 0.34, 0.37]               [0.33, 0.91, 0.28, 0.36, 0.5]
    
        5
  •  0
  •   Steven    5 年前

    我尝试了所有的解决方案,但都不是很有效(循环太慢)。

    我的解决方案是交叉连接并删除重复项。

    df_in = df.groupby('ID')['Value'].apply(list).reset_index(name="values_in")
    df_out = pd.merge(df, df, how="cross")
    df_out = df_out.loc[df_["ID_x"] != df_["ID_y"]].groupby('ID_x')['Value_y'].apply(list).reset_index(name="values_out")
    
    final_df = pd.merge(df_in, df_out, on="ID", how="full")