【问题标题】:Python: how to find the first nonzero in a multi-series dataframe?Python:如何在多系列数据框中找到第一个非零值?
【发布时间】:2017-11-14 06:22:57
【问题描述】:

我有一个包含 5 列索引的数据框。数据由 0 和 1 组成。我想找到每个系列中的第一个非零值并将它(并且只有它)乘以 100。

Date A B C D E 3/1/16 0 0 0 0 0 3/2/16 0 0 1 0 0 3/3/16 1 0 0 0 0 3/4/16 0 1 0 0 0 3/7/16 0 0 1 0 1 3/8/16 0 0 0 0 1 3/9/16 0 0 0 1 1 我尝试了以下代码,但没有成功。

for col in df.columns:
    idx = df[col].first_valid_index()
    df[col][idx] = df[col][idx]*100.

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    首先对所有数字列使用set_index,然后使用eq(与== 相同)和cumsum 的链创建布尔掩码并进行比较。

    然后按掩码和多选,最后reset_index

    df = df.set_index('Date')
    
    m = df.eq(1) & df.cumsum().eq(1)
    df[m] *= 100
    
    df = df.reset_index()
    print (df)
         Date    A    B    C    D    E
    0  3/1/16    0    0    0    0    0
    1  3/2/16    0    0  100    0    0
    2  3/3/16  100    0    0    0    0
    3  3/4/16    0  100    0    0    0
    4  3/7/16    0    0    1    0  100
    5  3/8/16    0    0    0    0    1
    6  3/9/16    0    0    0  100    1
    

    详情:

    print (df.cumsum())
            A  B  C  D  E
    Date                 
    3/1/16  0  0  0  0  0
    3/2/16  0  0  1  0  0
    3/3/16  1  0  1  0  0
    3/4/16  1  1  1  0  0
    3/7/16  1  1  2  0  1
    3/8/16  1  1  2  0  2
    3/9/16  1  1  2  1  3
    
    
    print (df.cumsum().eq(1))
                A      B      C      D      E
    Date                                     
    3/1/16  False  False  False  False  False
    3/2/16  False  False   True  False  False
    3/3/16   True  False   True  False  False
    3/4/16   True   True   True  False  False
    3/7/16   True   True  False  False   True
    3/8/16   True   True  False  False  False
    3/9/16   True   True  False   True  False
    
    print (df.eq(1))
                A      B      C      D      E
    Date                                     
    3/1/16  False  False  False  False  False
    3/2/16  False  False   True  False  False
    3/3/16   True  False  False  False  False
    3/4/16  False   True  False  False  False
    3/7/16  False  False   True  False   True
    3/8/16  False  False  False  False   True
    3/9/16  False  False  False   True   True
    

    m = df.eq(1) & df.cumsum(axis=1).eq(1)
    print (m)
                A      B      C      D      E
    Date                                     
    3/1/16  False  False  False  False  False
    3/2/16  False  False   True  False  False
    3/3/16   True  False  False  False  False
    3/4/16  False   True  False  False  False
    3/7/16  False  False   True  False  False
    3/8/16  False  False  False  False   True
    3/9/16  False  False  False   True  False
    

    设置:

    from pandas.compat import StringIO
    
    temp=u"""Date   A   B   C   D   E
    3/1/16  0   0   0   0   0
    3/2/16  0   0   1   0   0
    3/3/16  1   0   0   0   0
    3/4/16  0   1   0   0   0
    3/7/16  0   0   1   0   1
    3/8/16  0   0   0   0   1
    3/9/16  0   0   0   1   1"""
    df = pd.read_csv(StringIO(temp), sep="\s+")
    print (df)
    
         Date  A  B  C  D  E
    0  3/1/16  0  0  0  0  0
    1  3/2/16  0  0  1  0  0
    2  3/3/16  1  0  0  0  0
    3  3/4/16  0  1  0  0  0
    4  3/7/16  0  0  1  0  1
    5  3/8/16  0  0  0  0  1
    6  3/9/16  0  0  0  1  1
    

    【讨论】:

    • 我也给你点赞,我在第二个条件下遇到了困难。也可能有另一种方式,idxmax
    • @cᴏʟᴅsᴘᴇᴇᴅ - 谢谢,idxmax 也是我的第一个想法,但这里似乎更好的是 cumsum
    • 看我的回答,argmax 是可能的。
    • 其实我想测试所有的答案,你们能贴出创建df的代码吗?如果无论如何从文本中获取 df 会更好。我认为在 R 中有一个解决方法,但不知道 python。
    • 剪贴板面临问题,是否可以从变量创建 df?我试过 pd.read_table("""text,,,""", sep="\s+"),但失败了。
    【解决方案2】:

    我知道有一种方法可以在这里使用argmax

    df = df.set_index('Date')
    
    v = df.values
    v[v.argmax(0), np.arange(df.shape[1] - 1)] *= 100  
    df[:] = v
    
    df.reset_index()
    
    
    
         Date    A    B    C    D    E
    0  3/1/16    0    0    0    0    0
    1  3/2/16    0    0  100    0    0
    2  3/3/16  100    0    0    0    0
    3  3/4/16    0  100    0    0    0
    4  3/7/16    0    0  100    0    1
    5  3/8/16    0    0    0    0  100
    6  3/9/16    0    0    0  100    1
    

    得到了here的一点帮助。

    【讨论】:

      【解决方案3】:

      使用for 循环,我们可以做到

      cols = df.columns[df.columns != 'Date']
      for col in cols:
          idx = df[col][df[col] != 0].index[0]
          df[col][idx] = df[col][idx]*100
      

      【讨论】:

      • 我认为 pandas 和 r 也有同样的规则——没有循环;)
      • 您好,欢迎来到熊猫。很高兴在这里看到新面孔,所以你会得到支持。
      • @jezrael 谢谢,我不知道 pandas 中的所有功能都可以像你一样做一个非循环解决方案 :=)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-26
      • 2013-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多