首页 > 解决方案 > Pandas groupby 将嵌套的 ndarray 数组分配回数据帧

问题描述

我有一个数据集,我在其中使用 groupby 和基于两列的比较并获得结果 numpy 数组。我尝试做的是将它们放回数据框。

逻辑:我有这个df包含以下列的数据框:id、cluster、a、b。粘贴在这里用于复制目的:

individual  cluster a   b
9710556 0   180.82  140
9710556 0   180.82  140
9710556 0   202.32  145
9710556 1   218.32  145
9710556 1   250.82  140

我尝试为每一行查找每个 id (下面的 onIndiv 列)以及每个 id 和集群(下面的 onIndivCluster 列)中的 a、b 值的数量(在两个值中)都严格小于其他 a、b 值。这是我期望的期望输出:

individual  cluster a   b   onIndiv onIndivCluster
9710556 0   180.82  140 2   1
9710556 0   180.82  140 2   1
9710556 0   202.32  145 0   0
9710556 1   218.32  145 0   0
9710556 1   250.82  140 0   0

这是我想出的一个功能:

def ranker(df):
  values = df[["a", "b"]].values
  result = values[:, None] < values
  return np.logical_and.reduce(result, axis = 2).sum(axis = 1)

df.groupby("individual").apply(ranker)
Out[192]: 
id
9710556    [2, 2, 0, 0, 0]
dtype: object

small.groupby(["individual", "cluster"]).apply(ranker)

Out[169]:
individual  cluster
9710556     0          [1, 1, 0]
            1             [0, 0]
dtype: object

如何将这些结果分配给原始数据框以获得所需的输出?

标签: pythonpandasdataframepandas-groupby

解决方案


不幸的是,在这里应用想要聚合行,所以获取列表,所以使用一列 DataFrame 来防止它:

def ranker(df):
  values = df[["a", "b"]].values
  result = values[:, None] < values
  a = np.logical_and.reduce(result, axis = 2).sum(axis = 1)
  return pd.DataFrame({0:a}, index=df.index)

df['onIndiv'] = df.groupby("individual").apply(ranker)
df['onIndivCluster'] = df.groupby(["individual", "cluster"]).apply(ranker)
print (df)
   individual  cluster       a    b  onIndiv  onIndivCluster
0     9710556        0  180.82  140        2               1
1     9710556        0  180.82  140        2               1
2     9710556        0  202.32  145        0               0
3     9710556        1  218.32  145        0               0
4     9710556        1  250.82  140        0               0

或者在函数中添加新列,更灵活的解决方案是使用带有新列名的 lambda 函数:

def ranker(df, name):
  values = df[["a", "b"]].values
  result = values[:, None] < values
  df[name] = np.logical_and.reduce(result, axis = 2).sum(axis = 1)
  return df

df = df.groupby("individual").apply(lambda x: ranker(x, 'onIndiv'))
df = df.groupby(["individual", "cluster"]).apply(lambda x: ranker(x, 'onIndivCluster'))

print (df)
   individual  cluster       a    b  onIndiv  onIndivCluster
0     9710556        0  180.82  140        2               1
1     9710556        0  180.82  140        2               1
2     9710556        0  202.32  145        0               0
3     9710556        1  218.32  145        0               0
4     9710556        1  250.82  140        0               0

推荐阅读