将组迭代到数据帧

时间:2018-02-25 10:32:13

标签: python pandas

                 A   B
    0   2002-01-16   0
    1   2002-01-16   4
    2   2002-01-16  -2
    3   2002-01-16  11
    4   2002-01-16  12
    5   2002-01-17   0
    6   2002-01-17 -18
    7   2002-01-17  16
    8   2002-01-18   0
    9   2002-01-18  -1
    10  2002-01-18   4

results = {}
grouped = df.groupby("A")

for name, group in grouped:
    if (df["B"] >= 10).any():
        results[name] = df.loc[df["B"] >= 10].head(1)
        print(results[name])
    elif (df["B"] <= -10).any():
        results[name] = df.loc[df["B"] <= -10].head(1)
        print(results[name])
    else:
        results[name] = df.loc[df["B"] > -10, :].tail(1)
        print(results[name])

输出:

            A   B
3  2002-01-16  11
            A   B
3  2002-01-16  11
            A   B
3  2002-01-16  11

我希望迭代并为每个 A组 获得一个结果,并具备以下条件:

  • 如果任何 B列值>> 10或&lt; = -10,请将第一个添加到“结果”并跳到下一个组继续迭代。
  • 如果没有 B列值&gt; = 10或&lt; = -10,请将最后一个值添加到“results”并跳到下一个组继续迭代。

所需的输出是:

            A   B
3  2002-01-16  11
            A   B
6  2002-01-17 -18
            A   B
10 2002-01-18   4

3 个答案:

答案 0 :(得分:1)

这是另一种方法,遵循您的方法:

# we'll use this function to get output
def get_values(df):

    # check the condition
    if any(df.loc[(df["B"] >= 10) |(df["B"] <= -10),'B'].values > 0):
        # spit correct value
        val = df.loc[(df["B"] >= 10) |(df["B"] <= -10),'B'].head(1)
    else:
        val = df['B'].tail(1)  
    return val

df.groupby('A').apply(get_values)

A             
2002-01-16  3     11
2002-01-17  6    -18
2002-01-18  10     4
Name: B, dtype: int64

答案 1 :(得分:1)

您的代码包含两个阻止正确输出的错误。第一个,也就是最天堂的是,你没有在group循环中使用for。而是在完整的df帧上运行。这就是为什么每个条目都得到相同的结果。

修复后,您将获得几乎预期结果。但不完全是,由于你的第二个错误。根据您的说明,您希望将>= 10<= -10等同起来。但是,您的代码首先执行大于检查,如果该代码成功,它将生成您的输出。因此,组2002-01-17的结果将是16,而不是-18。

第二个问题的解决方法是确保您在同一个if子句中测试两个条件,通常使用or。但是,在您当前的情况下,可以使用绝对值(abs()运算符)将这两个测试折叠为一个。不过,这有点特殊情况(尽管很常见)。使用or来理解这一点和更一般的方法是很好的。

这会将案例数减少到两个,删除elif行。此外,可以进行一些小修改以增加可读性。合在一起会让你有类似的东西:

results = {}
grouped = df.groupby("A")

for name, group in grouped:
    if (abs(group["B"]) >= 10).any():
        results[name] = group[abs(group["B"]) >= 10].head(1)
    else:
        results[name] = group.tail(1)
    print(results[name])

生成所需的输出:

           A   B
3 2002-01-16  11
           A   B
6 2002-01-17 -18
            A  B
10 2002-01-18  4

答案 2 :(得分:0)

如果您不想使用循环,请尝试以下操作:

df["C"] = df["B"].apply(lambda x: abs(x)>=10)
df.groupby("A", as_index=False).apply(lambda x: x[x["C"]].head(1) if not x[x["C"]].empty else x.tail(1))[["A", "B"]]

结果

Out[315]:
            A           B
    0   3   2002-01-16  11
    1   6   2002-01-17  -18
    2   10  2002-01-18  4