【问题标题】:Calculate difference between first non-zero value and last non-zero value through multiple instances in Pandas Series?通过 Pandas 系列中的多个实例计算第一个非零值和最后一个非零值之间的差异?
【发布时间】:2017-06-02 16:10:21
【问题描述】:

我有一个 DataFrame,其中 col_c 列的值为 0,正整数,0,负整数,0。我想返回一个新列(col_d,如下所示),其值计算第一个非零值和最后一个非零值。原始 DataFrame 演示 col_c 值:

   col_a col_b col_c
 1  AB    0     0     
 2  AB    0     0     
 3  AB    1     1     
 4  AB    1     2     
 5  AB    1     5     
 6  AB    1     3     
 7  AB    0     0     
 8  AB    0     0     
 9  AB   -1    -1     
10  AB   -1    -2     
11  AB   -1    -5     
12  AB   -1    -3     
13  AB    0     0
14  AB    0     0

我想按如下方式返回一个 DataFrame,其中第 6 行和第 12 行中的值 2 从 col_c 计算为 (3-1) = 2 和 (-3 - -1) = -2:

   col_a col_b col_c col_d
 1  AB    0     0      0
 2  AB    0     0      0
 3  AB    1     1      0
 4  AB    1     2      0
 5  AB    1     5      0
 6  AB    1     3      2
 7  AB    0     0      0
 8  AB    0     0      0
 9  AB   -1    -1      0
10  AB   -1    -2      0
11  AB   -1    -5      0
12  AB   -1    -3      2
13  AB    0     0      0
14  AB    0     0      0

【问题讨论】:

  • 顺便说一句,-3 - (-1) == -2

标签: python pandas dataframe series


【解决方案1】:

高级

  • 找零:df.col_c.eq(0)
  • 使用cumsum 创建群组
  • -1 替换实际的零位,因为这是我关心的非零位
  • 使用agg 执行groupby
    • 'last' 获得小组最后一位
    • 'first' 获得小组第一
    • 'last_valid_index 找出放置位置
    • 删除 -1 组,因为那些是我不关心的零
  • 创建一个字典,键是last_valid_index 的结果,值是'last''first' 之间的差异
  • 使用assignindex.map 创建新列
    • index.map 需要一个可调用对象,所以我使用 dict.get 方法。但是,我们希望默认为零,以便 dict.get 可以采用默认值。

m = df.col_c.eq(0)
g = m.cumsum().mask(m, -1)

d = df.col_c.groupby(g).agg(['last', 'first', lambda x: x.last_valid_index()]).drop(-1)
k = dict(zip(d['<lambda>'], d['last'] - d['first']))

df.assign(col_d=df.index.map(lambda x: k.get(x, 0)))

   col_a  col_b  col_c  col_d
1     AB      0      0      0
2     AB      0      0      0
3     AB      1      1      0
4     AB      1      2      0
5     AB      1      5      0
6     AB      1      3      2
7     AB      0      0      0
8     AB      0      0      0
9     AB     -1     -1      0
10    AB     -1     -2      0
11    AB     -1     -5      0
12    AB     -1     -3     -2
13    AB      0      0      0
14    AB      0      0      0

【讨论】:

  • 删除了之前的感谢评论 - 再次感谢!这个问题的另一个补充:这个案例有一个单一的系列解决方案吗?这适用于系列(即 col_c 中的多个值)的实现。对于 col_c 中的单个值(假设 Series 段为 0、5、0 而不是之前的 0、1、5、0),是否也可以返回该单个值?让我知道我是否可以更好地表达这个问题 - 我很抱歉,因为我对发帖还比较陌生。再次感谢!
【解决方案2】:

您似乎正在计算最后两列之间的绝对差异,无论值是 0 还是非零。如果是这种情况,您可以这样做:

df['new'] = df.iloc[:,[-2,-1]].apply(lambda (x,y):abs(x-y), axis=1)

【讨论】:

  • 您的语法不正确,如果您将其修复为df.iloc[:,[-2,-1]].apply(lambda t:abs(t[0] - t[1]), axis=1),则会产生不正确的结果。此外,这取决于 col_b 始终具有 OP 从未说过的适当值。
【解决方案3】:

这是使用循环的另一种方式:

df['col_d'] = 0
count = 0
for row in range(0, len(df)-1):
    if df['col_c'][count] != 0 and df['col_c'][count+1] == 0:
        df['col_d'][count] = df['col_c'][count] - df['col_b'][count]
    count += 1

首先,创建列 d 并将所有行设置为 0。然后,遍历数据框并查找以下行:

  • c 列不等于 0
  • 在下面的行中,c 列确实等于 0

然后将该行中的d列设置为:c列减去b列。

【讨论】:

    猜你喜欢
    • 2015-11-05
    • 1970-01-01
    • 2022-11-30
    • 2023-01-18
    • 2017-12-18
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多