基于pandas / numpy中列中值的总和对行进行分组

b4wnujal  于 2023-04-18  发布在  其他
关注(0)|答案(3)|浏览(131)

我有一个表如下

我需要添加日期列的值的基础上,在consequtive行的值的总和。日期增量或保持不变的行的基础上,值的总和小于或等于最大值。

我的数据在excel里。
我想知道如何在python中使用pandas或numpy或任何其他库来实现这一点。
有什么建议吗?
谢谢
寻找指针

4c8rllxm

4c8rllxm1#

所以基本上你有以下输入:

x = [8, 1, 2, 4, 3, 6, 2]
threshold = 8

并希望创建组,这些组可能编码如下:

expected = [0, 1, 1, 1, 2, 3, 3]

您可以使用以下函数,该函数可能未进行优化(普通for循环):

def groupby_moving_sum_threshold(x, threshold):
    groups = []
    group_idx, total = 0, 0
    for n in x:
        total += n
        if total > threshold:
            group_idx += 1
            total = n
        groups.append(group_idx)
    return groups

它提供了良好的结果:

assert groupby_moving_sum_threshold(x, threshold) == expected

如果x输入是pandas数据框的一列,则使用它创建一个新列group
基于这个新专栏,你将能够实现你想要的:

df = pd.DataFrame({"rowid": list("abcdefg"), "value": x})

df["group"] = groupby_moving_sum_threshold(df["value"], threshold)
df["date"] = ...
6ojccjat

6ojccjat2#

下面是一个组合pandas/numpy的选项:

import numpy as np
import pandas as pd

MAX = df["value"].max()
​
arr = df["value"].mask(df["value"].eq(MAX), other=0).to_numpy(copy=True)
cs_func = np.frompyfunc(lambda a,b: a+b if a < MAX+1 else b, 2, 1)
​
ser = pd.Series(cs_func.accumulate(arr))
​
offset = (ser.eq(df["value"]) | ser.gt(MAX)).cumsum()
​
df["date"] = (pd.Timestamp.today() + pd.to_timedelta(offset, unit="D")).dt.strftime("%m/%d/%y")
​

输出:

print(df)

  rowid  value      date
0     a      8  04/14/23
1     b      1  04/15/23
2     v      2  04/15/23
3     d      4  04/15/23
4     e      3  04/16/23
5     f      6  04/17/23
6     g      2  04/17/23
  • 中间体:*
rowid  value  arr ser  offset      date
0     a      8    0   0       0  04/14/23
1     b      1    1   1       1  04/15/23
2     v      2    2   3       1  04/15/23
3     d      4    4   7       1  04/15/23
4     e      3    3  10       2  04/16/23
5     f      6    6   6       3  04/17/23
6     g      2    2   8       3  04/17/23
bttbmeg0

bttbmeg03#

你可以利用pandas的apply方法。
这是一个简单的例子,其中日期是一个整数,但可以相当容易地修改为您所需的日期格式。

df = pd.DataFrame([{"row_id": 'a', "value": 2}, {"row_id": 'b', "value": 6}, {"row_id": 'c', "value": 2}, {"row_id": 'c', "value": 7},  {"row_id": 'c', "value": 3}])
sum = 0
START_DATE = 1
date = START_DATE  # date at fist row

def func(row):
    global sum
    global date
    sum += row.value
    if row.name == 0:  # skip first row
        return START_DATE

    if sum >= 8:  # reset threshold increase date
        sum = 0 
        date += 1
    return date

df["date"] = START_DATE  # initialize to START_DATE
df["date"] = df.apply(func, axis=1)  # apply function row-wise

print(df.to_string())```
指数行ID价值日期
0a1
1B
c
c
c

相关问题