【问题标题】:Enumerate rows for each dtaaframe group based on conditions根据条件枚举每个数据框组的行
【发布时间】:2017-09-17 15:35:48
【问题描述】:

我想使用某些条件重新枚举给定df 中的行。我的问题是这个question 的扩展。

df 的示例:

   ind  seq  status 
0   1   2    up
1   1   3    mid
2   1   5    down
3   2   1    up
4   2   2    mid
5   2   3    down
6   3   1    up
7   3   2    mid
8   3   3    oth 

df 包含代表ind 列。 seq 列可能包含一些错误数据。这就是我想添加另一列seq_corr 以更正基于某些条件的seq 枚举的方式:

  • status 列中组中的第一个值等于up
  • status 列中组中的最后一个值等于 downoth
  • 在所有其他情况下,复制来自seq 列的编号。

我知道执行此操作的合乎逻辑的方法,但我在如何将其转换为 Python 时遇到了一些麻烦。尤其是在正确切片和访问每个组的第一个和最后一个元素时。

你可以在下面找到我不工作的代码:

 def new_id(x):
    if (x.loc['status',0] == 'up') and ((x.loc['status',-1]=='down') or (x['status',-1]=='oth')):
        x['ind_corr'] = np.arange(1, len(x) + 1)
    else:
        x['seq_corr']= x['seq']
    return x

 df.groupby('ind', as_index=False).apply(new_id)

预期结果:

   ind  seq  status  seq_corr
0   1   2    up       1
1   1   3    mid      2
2   1   5    down     3
3   2   1    up       1
4   2   2    mid      2
5   2   3    down     3
6   3   5    up       1
7   3   2    mid      2
8   3   7    oth      3

希望有人能指出任何解决方案。

【问题讨论】:

    标签: python pandas dataframe group-by


    【解决方案1】:

    让我们试试df.groupby,然后是applyconcatenation。

    vals = df.groupby('ind').apply(
           lambda g: np.where(g['status'].iloc[0] == 'up' 
                           or g['status'].iloc[-1] in {'down', 'oth'},
          np.arange(1, len(g) + 1), g['seq'])
    ).values
    
    df['seq_corr'] = np.concatenate(vals)
    

    df
       ind  seq status  seq_corr
    0    1    2     up         1
    1    1    3    mid         2
    2    1    5   down         3
    3    2    1     up         1
    4    2    2    mid         2
    5    2    3   down         3
    6    3    1     up         1
    7    3    2    mid         2
    8    3    3    oth         3
    

    【讨论】:

    • 谢谢你,效果很好!就一个问题。如果status不满足任何条件,我想复制seq号码怎么办?
    • @Michal 将or 替换为and
    • @cᴏʟᴅsᴘᴇᴇᴅ 我对您的答案进行了一些编辑。你可以用你的话编辑它。
    • @Bharathshetty 布尔表达式没问题。有必留或。此代码重新枚举所有序列号。
    • @Michal 我的回答会有帮助吗?
    【解决方案2】:

    使用 groupby cumcount 的另一种方法。要选择第一行和最后一行,我们可以使用 head 和 tail 方法并合并它们的索引。我认为这可能对您的第二个问题有所帮助

    df['seq_corr'] = df.groupby('ind').cumcount()+1
    idx = df.groupby('ind').head(1).index.union(df.groupby('ind').tail(1).index)
    
    df.loc[idx,'seq_corr'] = np.where(~df.loc[idx,'status'].isin(['up','down','oth']),
                                        df.loc[idx,'seq'],df.loc[idx,'seq_corr'])
    

    样本输出:

    ind seq 状态 seq_corr 0 1 2 向上 1 1 1 3 中 2 2 1 5 舞蹈 5 3 2 1 向上 1 4 2 2 中 2 5 2 3 下降 3 6 3 1 上升 1 7 3 2 中 2 8 3 3 其他 3

    【讨论】:

    • 谢谢@Bharath shetty。 isin([...]) 是否考虑了 AND 语句的所有条件?我的想法是也有OR。但无论如何,我已经将@cᴏʟᴅsᴘᴇᴇᴅ 答案与我的想法合并,看起来一切正常。我将在下面发布解决方案。
    • 这将根据您的OR 条件正常工作,因为我们正在获取第一行和最后一行分组数据。这是期望的输出,对吧?你遇到过什么问题吗?
    【解决方案3】:

    感谢@cᴏʟᴅsᴘᴇᴇᴅ 我已经更正了我的代码。查看第一次测试,一切正常。

     def new_id(x):
        if (x['status'].iloc[0] == 'up') and ((x['status'].iloc[-1]=='down') or (x['status'].iloc[-1]=='oth')):
        x['seq_corr'] = np.arange(1, len(x) + 1)
        else:
        x['seq_corr']= x['seq']
        return x
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-13
      • 1970-01-01
      • 2018-01-27
      • 2017-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多