从分组数据框中获取一列,该列具有每组中另一列的两个最大值的某些差异

Getting a column from a grouped dataframe having certain difference of two largest values of another column in each group

我的数据框 df 是:

    Election Year   Votes   Party   Region
  0   2000           50      A       a
  1   2000           100     B       a
  2   2000           70      C       a
  3   2000           26      A       b
  4   2000           180     B       b
  5   2000           100     C       b 
  6   2000           120     A       c
  7   2000           46      B       c
  8   2000           80      C       c
  9   2005           129     A       a
  10  2005           46      B       a
  11  2005           95      C       a
  12  2005           60      A       b
  13  2005           23      B       b
  14  2005           95      C       b
  15  2005           16      A       c
  16  2005           65      B       c
  17  2005           35      C       c

我想获取每年最大的两个政党的选票差小于 50 的地区。所以期望的输出是:

 Region
  a
  c

在这两个地区,每年前两党的票数差距小于 50。

我尝试使用“选举年”和“地区”进行分组,然后按降序对投票进行排序。但是我无法检查每年每个地区的前两名票数之间的差异是否小于50。

如何获得所需的输出?

我会使用 .pivot:

df = df.pivot(
    index=["Region", "Election Year"], columns="Party", values="Votes"
)
df["diff"] = df.apply(
    lambda x: x.sort_values(ascending=False).head(2).diff()[-1] * -1, axis=1
)
x = df.groupby(level=0)["diff"].apply(lambda x: (x < 50).all())
print(pd.DataFrame(x.index[x]))

打印:

  Region
0      a
1      c

步骤:

df = df.pivot(
    index=["Region", "Election Year"], columns="Party", values="Votes"
)

创造:

Party                   A    B    C
Region Election Year               
a      2000            50  100   70
       2005           129   46   95
b      2000            26  180  100
       2005            60   23   95
c      2000           120   46   80
       2005            16   65   35
df["diff"] = df.apply(
    lambda x: x.sort_values(ascending=False).head(2).diff()[-1] * -1, axis=1
)

创造:

Party                   A    B    C  diff
Region Election Year                     
a      2000            50  100   70  30.0
       2005           129   46   95  34.0
b      2000            26  180  100  80.0
       2005            60   23   95  35.0
c      2000           120   46   80  40.0
       2005            16   65   35  30.0
x = df.groupby(level=0)["diff"].apply(lambda x: (x < 50).all())

创造:

Region
a     True
b    False
c     True

从你的想法出发,排序(sort_values)+分组(GroupBy),然后求差值diff(),得到票数差值:

>>> df = df.sort_values(['Votes'])
>>> votes_diff = df.groupby(['Election Year', 'Region'])['Votes'].diff()

我们可以加入原始数据框并在索引上重新排序以查看原始数据发生了什么:

>>> df.join(votes_diff.rename('Δ votes')).sort_index()
    Election Year  Votes Party Region  Δ votes
0            2000     50     A      a      NaN
1            2000    100     B      a     30.0
2            2000     70     C      a     20.0
3            2000     26     A      b      NaN
4            2000    180     B      b     80.0
5            2000    100     C      b     74.0
6            2000    120     A      c     40.0
7            2000     46     B      c      NaN
8            2000     80     C      c     34.0
9            2005    129     A      a     34.0
10           2005     46     B      a      NaN
11           2005     95     C      a     49.0
12           2005     60     A      b     37.0
13           2005     23     B      b      NaN
14           2005     95     C      b     35.0
15           2005     16     A      c      NaN
16           2005     65     B      c     30.0
17           2005     35     C      c     19.0

因此在每次选举中,每个政党现在都有一个值 Δ votes,即它比下一个政党多获得多少选票。每次选举中最小的政党 NaN 计票。

现在我们希望在每次选举中获得最大的 2 个政党之间的差异,即 Δ votes 代表得票最多的那一行。我们可能会使用 idxmax,但由于数据框已经按投票计数排序,我们也可以只使用 last.

>>> top_vote_diff = votes_diff.groupby([df['Election Year'], df['Region']]).last()
>>> top_vote_diff
Election Year  Region
2000           a         30.0
               b         80.0
               c         40.0
2005           a         34.0
               b         35.0
               c         30.0
Name: Votes, dtype: float64

现在检查该地区的所有选举是否少于 50 lt(50)

>>> criteria = top_vote_diff.lt(50).groupby('Region').all()
>>> criteria
Region
a     True
b    False
c     True
Name: Votes, dtype: bool
>>> pd.Series(criteria.index[criteria])
0   a
1   c
Name: Region, dtype: object