在pandas groupby之后合并成对的行,如果在df中没有两次出现ID,则给出NaN值

时间:2019-06-21 18:23:01

标签: python python-3.x pandas pandas-groupby

我有一个包含ID列id的单个数据框,并且我知道该ID将完全存在于数据框的一行(“不匹配”)或两行(“匹配”)中。

  • 为了选择不匹配的行和匹配的行对,我可以在ID列上使用groupby
  • 现在,对于每个组,我想从第二(对)行中提取一些列,对其进行重命名,然后将其复制到第一行。然后,我可以舍弃所有第二行,并返回一个包含所有修改后的第一行(每个组)的单个数据框。
  • 没有第二行(不匹配)的地方-可以将NaN放在适当的位置。

为说明这一点,请参见下表id=13是匹配对,但是id=2不匹配:

entity id partner value
A      1  B       200
B      1  A       300
A      2  B       600
B      3  C       350
C      3  B       200

最终的转换应使我具备以下条件:

entity id partner entity_value partner_value
A      1  B       200          300
A      2  B       600          NaN
B      3  C       350          200

让我感到困惑的是如何提出一种通用方法,即从group 2之后的第2行获取匹配的partner_value,并在groupby之后复制到第1行,这种方法在没有匹配id的情况下也可以使用。 / p>

3 个答案:

答案 0 :(得分:3)

解决方案(这很棘手):

dfg = df.groupby('id', sort=False)

# Create 'entity','id','partner','entity_value' from the first row...
df2 = dfg['entity','id','partner','value'].first().rename(columns={'value': 'entity_value'})

# Now insert 'partner_value' from those groups that have a second row...
df2['partner_value'] = nan
df2['partner_value'] = dfg['value'].nth(n=1)

   entity  id partner  entity_value  partner_value
id                                                
1       A   1       B           200          300.0
2       A   2       B           600            NaN
3       B   3       C           350          200.0

这很难上班。简短的答案是,尽管原则上pd.groupby(...).agg(...)允许您指定(column, aggregate_function)could then chain those into a rename的元组列表,但这在这里不起作用,因为我们试图做两个在value列上分别进行聚合操作,并重命名两个结果(您得到pandas.core.base.SpecificationError: Function names must be unique, found multiple named value)。

其他并发症:

  • 我们不能直接 使用groupby.nth(n),乍一看听起来很有用,除了它仅在DataFrame而不是像df['value']这样的Series上使用,而且它会静默删除组没有第n个元素,不是我们想要的。 (但是它确实保留了索引,因此我们可以通过首先将列初始化为全NaN,然后​​如上所述有选择地插入该列来使用它。)
  • 在任何情况下,pd.groupby.agg()甚至都不会通过仅将'nth'作为agg_func名称来调用nth(),因为nth()缺少其n论点您必须声明一个lambda。
  • 我尝试定义以下函数second_else_nan以在agg()中使用,但经过很多努力后,由于多种原因,我无法使它正常工作,其中只有一个是您不能在同一列上进行两次汇总:

代码:

def second_else_nan(v):
    if v.size == 2:
        return v[1]
    else:
        return pd.np.nan

(即内置dict.get(key, default)列表中的等效项)

答案 1 :(得分:1)

我会这样做。首先,获取第一个值:

df_grouped = df.reset_index().groupby('id').agg("first")

然后检索重复的值并将其插入:

df_grouped["partner_value"] = df.groupby("id")["value"].agg("last")

唯一的是,如果没有重复值(而不是NaN),您将有一个重复的值。

答案 2 :(得分:0)

这样的事情怎么办?

...
@Test
public void initSomething() {
    doSomething(param1);
}

@Test(retryAnalyzer = ThreeRetries.class, dependsOnMethods = "initSomething")
public void testStuff() {
    String var1;
    String var2;

    assertStuff(var1, var2);
}

按ID对数据分组,取第一行,为每个组取“值”列的总和,然后从第一行减去“值”。然后将结果列中的0替换为np.nan(此处假设“值”列中的数据永远不会为0)