选择具有条件的组中的行

时间:2018-03-04 14:56:09

标签: python pandas

        A     B     C
0    blue  14.5  14.0
1    blue  14.0  14.0
2    blue  13.5  14.0
3    blue  12.0  14.0
4    blue  10.5  14.0
5   green  20.0  19.0
6   green  19.0  19.0
7   green  18.5  19.0
8   green  18.0  19.0
9   green  17.5  19.0
10  green  16.0  19.0

我想创建一个新的df1,其中包含下一个条件,每个 A组(“蓝色”和“绿色”):

  • 选择 B = C 的行和 B = C-1
  • 的行
  • 如果组中不存在满足条件(B = C-1)的任何 B值,请进一步选择下一行这将是对应的。例如,在“蓝色组”中, B = C - 1 14.0 - 1 = 13.0 。由于不存在任何13.0“蓝色组”,请选择df中存在的下一行,即:

    3 blue 12.0 14.0

df1应为:

       A     B     C
1   blue  14.0  14.0
3   blue  12.0  14.0
6  green  19.0  19.0
8  green  18.0  19.0

我试过了:

df1 = df[(df["B"] == df["C"]) | (df["B"] == df["C"]-1)]

3 个答案:

答案 0 :(得分:0)

使用:

  • 首先创建帮助列DC按计数减去GroupBy.cumcount - 获取所有可能的值B == C-0,1,2,3...
  • 使用groupby按群组isin进行过滤,删除列D
  • 如有必要,请按sort_values
  • 排序AB
  • 按计数器boolean indexing
  • 过滤每组前2行
df['D'] = df['C'].sub(df.groupby('A').cumcount())
df = df[df.groupby('A').apply(lambda x: x['B'].isin(x['D'])).values].drop('D',1)
df = df.sort_values(['A','B'], ascending=[True, False])
df = df[df.groupby('A').cumcount() < 2]
print (df)
       A     B     C
1   blue  14.0  14.0
3   blue  12.0  14.0
6  green  19.0  19.0
8  green  18.0  19.0

答案 1 :(得分:0)

条件:

  • row where B = C - 1
  • if not exists B = C - 1, then row with largest B, such that B < C - 1

可以组合成1个条件:

row with largest B, such that B <= C - 1

如果您的数据是第一个条件,即所有组都存在row where B = C,那么您可以像这样编写投影:

res = df[(df.B == df.C) | (df.B <= df.C - 1)].sort_values('B').groupby('A').tail(2)

# output:

       A     B     C
3   blue  12.0  14.0
1   blue  14.0  14.0
8  green  18.0  19.0
6  green  19.0  19.0

如果第一个条件B = C与某些组不匹配,则使用pd.concat结合两个单独的投影:

res = pd.concat([df[df.B == df.C], 
                 df[df.B <= df.C - 1].sort_values('B').groupby('A').tail(1)])

# or you can split this long line into a couple of lines for better 
# readibility
# p1 = df[df.B == df.C]
# p2 = df[df.B <= df.C - 1].sort_values('B').groupby('A').tail(1)
# res = pd.concat([p1, p2])
# output:

       A     B     C
1   blue  14.0  14.0
6  green  19.0  19.0
3   blue  12.0  14.0
8  green  18.0  19.0

如您所见,对于第二个解决方案,行不会按您在问题中指定的顺序返回,因此如果您需要有序结果,则可能需要进一步的多列排序:

res.sort_values(['C', 'B'], ascending=[True, False])

答案 2 :(得分:0)

对于第二个条件:B = C - 1

  • 我们可以设置条件B - C <= -1然后
  • 在每个组中找到满足此条件的第一行的索引。

    idx_cond = df.groupby("A").apply(
                   lambda x: x.where(x.B-x.C <= -1).first_valid_index())
    # A
    # blue     3
    # green    8
    # dtype: int64
    pd.concat([df[df.B == df.C], df.loc[idx_cond]])