【问题标题】:Getting rows for increasing values of a column in each group in grouped dataframe获取行以增加分组数据框中每个组中列的值
【发布时间】:2021-08-28 10:51:42
【问题描述】:

我的数据框df 是:

data = {'Election Year':['2000', '2000','2000','2000','2000','2000','2000','2000','2000','2005','2005','2005','2005','2005','2005','2005','2005','2005', '2010', '2010','2010','2010','2010','2010','2010','2010', '2010'],
    'Votes':[30, 50, 20, 26, 30, 45, 20, 46, 80, 60, 46, 95, 60, 10, 95, 16, 65, 35, 50, 100, 70, 26, 180, 100, 120, 46, 80], 
    'Party': ['A', 'B', 'C', 'A', 'B', 'C','A', 'B', 'C','A', 'B', 'C','A', 'B', 'C','A', 'B', 'C', 'A', 'B', 'C','A', 'B', 'C','A', 'B', 'C'],
    'Region': ['a', 'a', 'a', 'b', 'b', 'b','c', 'c', 'c','a', 'a', 'a', 'b', 'b', 'b','c', 'c', 'c','a', 'a', 'a', 'b', 'b', 'b','c', 'c', 'c']}
df = pd.DataFrame(data)
df

    
    Election Year   Votes   Party   Region
  0   2000           30      A       a
  1   2000           50      B       a
  2   2000           20      C       a
  3   2000           26      A       b
  4   2000           30      B       b
  5   2000           45      C       b 
  6   2000           20      A       c
  7   2000           46      B       c
  8   2000           80      C       c
  9   2005           60      A       a
  10  2005           66      B       a
  11  2005           95      C       a
  12  2005           60      A       b
  13  2005           10      B       b
  14  2005           95      C       b
  15  2005           16      A       c
  16  2005           65      B       c
  17  2005           35      C       c
  18  2010           50      A       a
  19  2010           100     B       a
  20  2010           70      C       a
  21  2010           26      A       b
  22  2010           180     B       b
  23  2010           100     C       b 
  24  2010           120     A       c
  25  2010           46      B       c
  26  2010           80      C       c

我希望在接下来的 2 次选举中,2000 年的前两个政党(就获得最大总票数而言)不断增加票数的地区.. 所以想要的输出是:

   Party   Region
     B        a
     B        c
     C        b

首先,我尝试根据 2000 年的总票数获得前两个政党。这是给政党“C”和“B”。

df1=df['Election Year'].eq('2000')
top_2=df[m].groupby(['Election Year','Party'],as_index=False) 
       ['Votes'].sum().sort_values('Votes',ascending=False).head(2)['Party'].values
top_2

这给了“C”和“B”方。

现在如何查看这些政党在随后几年的投票增加的地区?

【问题讨论】:

标签: python pandas dataframe data-science


【解决方案1】:
  • 2010年首先建立两个最高票数的政党
  • 然后在未来几年,分析政党/地区组合的升序票数和总票数
  • 最终选出符合条件的派对/地区配对
  • 我所看到的这种逻辑是可行的,但给你的输出却不同
data = {'Election Year':['2000', '2000','2000','2000','2000','2000','2000','2000','2000','2005','2005','2005','2005','2005','2005','2005','2005','2005', '2010', '2010','2010','2010','2010','2010','2010','2010', '2010'],
    'Votes':[30, 50, 20, 26, 30, 45, 20, 46, 80, 60, 46, 95, 60, 10, 95, 16, 65, 35, 50, 100, 70, 26, 180, 100, 120, 46, 80], 
    'Party': ['A', 'B', 'C', 'A', 'B', 'C','A', 'B', 'C','A', 'B', 'C','A', 'B', 'C','A', 'B', 'C', 'A', 'B', 'C','A', 'B', 'C','A', 'B', 'C'],
    'Region': ['a', 'a', 'a', 'b', 'b', 'b','c', 'c', 'c','a', 'a', 'a', 'b', 'b', 'b','c', 'c', 'c','a', 'a', 'a', 'b', 'b', 'b','c', 'c', 'c']}
df = pd.DataFrame(data)
# get top parties in 2000
topp = (
    df.loc[df["Election Year"].eq("2000")].groupby("Party").agg({"Votes": "sum"})
    .sort_values("Votes", ascending=False)
    .head(2)
)


def f(df):
    # test that year by year the votes are increasing.  also provide total votes for final step
    return pd.Series(
        {
            "ascending": (~df["Votes"].lt(df["Votes"].shift())).all(),
            "Votes": df["Votes"].sum(),
        }
    )


df2 = (
    df.loc[df["Party"].isin(topp.index) &
           df["Election Year"].gt("2000")].groupby(
               ["Party", "Region"], as_index=False
           ).apply(f)
)

# final step - filter those with ascending votes and pick out part/region that have most votes
df2.loc[df2["ascending"]].sort_values(["Region", "Votes"], ascending=[1, 0]).groupby("Region", as_index=False).first()

输出

Region Party ascending Votes
0 a B True 146
1 b C True 195
2 c C True 115

打开逻辑

  • 复杂的步骤是找到投票增加的政党地区组合
  • 这是一种提供更高透明度的替代方法。它使用 named aggregations 而不是 apply() 并输出更多正在考虑的数据
df2 = (
    df.loc[df["Party"].isin(topp.index) & df["Election Year"].gt("2000")]
    .groupby(["Party", "Region"], as_index=False)
    .agg(
        VoteDtl=("Votes", list),
        Votes=("Votes", "sum"),
        VotesS=("Votes", lambda s: s.shift(-1).fillna(10 ** 6).tolist()),
        Asc=("Votes", lambda s: s.shift(-1).fillna(10 ** 6).gt(s).all()),
    )
)

df2

Party Region VoteDtl Votes VotesS Asc
0 B a [46, 100] 146 [100.0, 1000000.0] True
1 B b [10, 180] 190 [180.0, 1000000.0] True
2 B c [65, 46] 111 [46.0, 1000000.0] False
3 C a [95, 70] 165 [70.0, 1000000.0] False
4 C b [95, 100] 195 [100.0, 1000000.0] True
5 C c [35, 80] 115 [80.0, 1000000.0] True

【讨论】:

  • 感谢您的宝贵时间和回答。能不能用更简单的方法解决?我对此感到不知所措。
  • 我已更新以在 groupby / aggregate 阶段提供更多透明度,以找到投票增加的组合
【解决方案2】:

我喜欢 Rob Raymond 的回答,但我只想强调一些可能对解决此类问题有用的东西。对于这种分析,最好以“Party”和“Region”列作为索引来查看数据。

如果我们这样做

grps = ["Party", "Region"]  # I do this because we will use these later
df = df.set_index(grps).sort_index()

然后df 现在看起来像

             Election Year  Votes
Party Region
A     a               2000     30
      a               2005     60
      a               2010     50
      b               2000     26
      b               2005     60
      b               2010     26
      c               2000     20
      c               2005     16
      c               2010    120
B     a               2000     50
      a               2005     46
      a               2010    100
      b               2000     30
      b               2005     10
      b               2010    180
      c               2000     46
      c               2005     65
      c               2010     46
C     a               2000     20
      a               2005     95
      a               2010     70
      b               2000     45
      b               2005     95
      b               2010    100
      c               2000     80
      c               2005     35
      c               2010     80

我认为这更容易通过肉眼研究进行一些交叉检查,例如根据我对您问题的理解,唯一每年投票数增加的政党/地区是“C/b”,其中有 45 票2000 年,2005 年 95 票,2010 年 100 票。

但是如果数据太大而无法查看怎么办。那么我们可以按新索引进行分组(记住现在是“Party”和“Region”)并将diff 方法应用于“Votes”列。我们会将这个结果分配回一个名为“Vote Diff”的新列。

df["Vote Diff"] = df.groupby(grps)["Votes"].diff()

现在df

             Election Year  Votes  Vote Diff
Party Region
A     a               2000     30        NaN
      a               2005     60       30.0
      a               2010     50      -10.0
      b               2000     26        NaN
      b               2005     60       34.0
      b               2010     26      -34.0
      c               2000     20        NaN
      c               2005     16       -4.0
      c               2010    120      104.0
B     a               2000     50        NaN
      a               2005     46       -4.0
      a               2010    100       54.0
      b               2000     30        NaN
      b               2005     10      -20.0
      b               2010    180      170.0
      c               2000     46        NaN
      c               2005     65       19.0
      c               2010     46      -19.0
C     a               2000     20        NaN
      a               2005     95       75.0
      a               2010     70      -25.0
      b               2000     45        NaN
      b               2005     95       50.0
      b               2010    100        5.0
      c               2000     80        NaN
      c               2005     35      -45.0
      c               2010     80       45.0

现在我们可以很容易地看到投票的上升和下降时间。对于您想要做的事情,我们现在不太关心 2000 年,因此我们可以在下一部分使用 drona 安全地删除带有 NaN 的行。

我们现在需要过滤 Party/Region 组,只保留组中“Vote diff”的所有值都为正的那些(即投票逐年增加)。我们可以在groupby 对象上使用filter 来做到这一点。我们需要一个小函数来测试这是否属实,这里我使用了lambda,但你也可以直接定义它。

out = df.dropna().groupby(grps).filter(lambda x: (x["Vote Diff"] > 0).all())

给予

             Election Year  Votes  Vote Diff
Party Region
C     b               2005     95       50.0
      b               2010    100        5.0

瞧!我们看到 C 党/b 区是唯一一个得票同比增长的政党。

我们尚未研究如何将其与您的顶级派对要求结合起来,但如果您有顶级派对列表,那么它是直截了当的(对您的 top_2 代码稍作修改)

top_2 = (df[df["Election Year"] == "2000"]
           .groupby("Party")["Votes"].sum()
           .nlargest(2))
out.loc[top_2.index]

把它们放在一起

top_2 = (df[df["Election Year"] == "2000"]
           .groupby("Party")["Votes"].sum()
           .nlargest(2))

grps = ["Party", "Region"]
df = df.set_index(grps).sort_index()
df["Vote Diff"] = df.groupby(grps)["Votes"].diff()
df.dropna().groupby(grps).filter(lambda x: (x["Vote Diff"] > 0).all()).loc[top_2.index]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-15
    • 2019-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-12
    相关资源
    最近更新 更多