【问题标题】:Creating a new column based on lagged/changing variable根据滞后/变化的变量创建新列
【发布时间】:2019-08-18 21:02:29
【问题描述】:

更新

我有一个如下所示的 df:

print(df)

           id  rank  a  
date                      
2000-01-01  1   1.0  0  
2000-01-01  2   3.0  0  
2000-01-01  3   2.0  0  
2000-01-01  4   0.0  0  
2000-01-02  1   2.0  0
2000-01-02  2   3.0  0  
2000-01-02  3   2.0  0  
2000-01-02  4   1.0  0
2000-01-03  1   3.0  0 
2000-01-03  2   2.0  0 
2000-01-03  3   1.0  0 
2000-01-03  4   1.0  0   

我想创建一个新变量 a,如果 rank 与上个月相比发生变化,则该变量等于 1。例如,在 2000-01-01 中,rank 是 3.0,而在 2000-01-02 中它更改为 2.0。我希望此更改与 a 中的 1 相对应,如果没有更改,则保持 0。我也想分组 id。此外,排名只能在每个时期增加 1。

预期输出

           id  rank  a  
date                      
2000-01-01  1   1.0  1 
2000-01-01  2   3.0  1  
2000-01-01  3   2.0  1  
2000-01-01  4   0.0  1  
2000-01-02  1   2.0  1
2000-01-02  2   3.0  0  
2000-01-02  3   2.0  0  
2000-01-02  4   1.0  1
2000-01-03  1   3.0  1 
2000-01-03  2   2.0  1 
2000-01-03  3   1.0  1 
2000-01-03  4   1.0  0   

任何帮助都会很棒!

【问题讨论】:

  • a 看起来不像 variable
  • a 中的第一个值是缺失值吗?还是空字符串?
  • 如果排名一步变化 >1,您可能应该澄清预期的输出。
  • 更新了,因为我现在也需要与id 分组!
  • @oceanbeach96 - 已编辑答案。

标签: python pandas dataframe


【解决方案1】:

使用Series.diffSeries.abs,如果可能的区别更像1 使用Series.clip

df['a'] = df['rank'].diff().abs().clip(upper=1)

如果差异总是只有1:

df['a'] = df['rank'].diff().abs()

如果需要将第一个值设置为0:

df['a'] = df['rank'].diff().fillna(0).ne(0).astype(int)

编辑答案:

df['a1'] = df.groupby('id')['rank'].diff().ne(0).astype(int)
print (df)
          date  id  rank  a  a1
0   2000-01-01   1   1.0  1   1
1   2000-01-01   2   3.0  1   1
2   2000-01-01   3   2.0  1   1
3   2000-01-01   4   0.0  1   1
4   2000-01-02   1   2.0  1   1
5   2000-01-02   2   3.0  0   0
6   2000-01-02   3   2.0  0   0
7   2000-01-02   4   1.0  1   1
8   2000-01-03   1   3.0  1   1
9   2000-01-03   2   2.0  1   1
10  2000-01-03   3   1.0  1   1
11  2000-01-03   4   1.0  0   0

【讨论】:

    【解决方案2】:

    使用shift

    import pandas as pd
    df = pd.DataFrame({"rank": [3.0, 2.0, 2.0, 2.0, 1.0]})
    
    df['a'] = (df['rank'] - df['rank'].shift(1)).abs()
    print(df)
    

    输出

       rank    a
    0   3.0  NaN
    1   2.0  1.0
    2   2.0  0.0
    3   2.0  0.0
    4   1.0  1.0
    

    编辑

    如果你想用空字符串替换NaN

    df['a'] = df['a'].fillna('').astype(str)
    

    编辑 2

    使用np.where,由于上面的 sn-p 会给出实际的差异,因此使用这种方法会给你 1 表示差异,否则为 0:

    import pandas as pd
    df = pd.DataFrame({"rank": [3.0, 12.0, 2.0, 2.0, 1.0]})
    
    df['a'] = np.where((df['rank'] - df['rank'].shift(1)).abs() > 0, 1, 0)
    print(df)
    

    【讨论】:

    • 这假设排名变化正好 +-1 或根本没有变化
    • 它运行,但输出例如。 2 而我认为所要求的是指示功能已发生的变化。
    【解决方案3】:

    您可以使用np.select 完成此操作

    df0 = df.shift()
    cond1 = df0['rank'].isnull()   # to set first row nan
    cond2 = df0['rank'] != df['rank']
    
    df['a'] = np.select([cond1,cond2], [0,1], 0)
    
    print(df)
    

    【讨论】:

      【解决方案4】:
      d['a'] = (d['rank'].shift() == d['rank']).map({True:0, False:1})
      

      注意a 列的第一个元素是1。如果您不需要它,请将其删除。
      希望对你有帮助。

      【讨论】:

        【解决方案5】:

        这也可以通过使用Series.diff() 并将一系列布尔值直接转换为整数来完成:

        df['a']=df['rank'].diff().eq(-1).astype(int)
        

        【讨论】:

          猜你喜欢
          • 2020-02-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-11-01
          • 1970-01-01
          • 2023-02-07
          • 2018-07-04
          相关资源
          最近更新 更多