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组 获得一个结果,并具备以下条件:
所需的输出是:
A B
3 2002-01-16 11
A B
6 2002-01-17 -18
A B
10 2002-01-18 4
答案 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