熊猫:撤消累积(例如累积总和)

时间:2018-09-11 11:52:16

标签: python excel pandas running-total

我收到了带有累积数字的数据。是否有一种聪明的方法来减少数据的累积量,所以我每个月都有它,而不是彼此堆叠?

(在此处检查示例xlsx:https://docs.google.com/spreadsheets/d/1yELrJdZmi3CFJccYSi5U6GGDW-Awp5spHDnsDyshBe0/edit?usp=sharing。)

示例输入:

Date    SalesRep    itemA   itemB
01-01-2018  Jakob   5       10
01-01-2018  Adomas  10      20
01-01-2018  Thomas  15      30
01-02-2018  Jakob   50      30
01-02-2018  Adomas  100     40
01-02-2018  Thomas  150     65

所需的输出:

Date    SalesRep    itemA   itemB
01-01-2018  Jakob   5       10
01-01-2018  Adomas  10      20
01-01-2018  Thomas  15      30
01-02-2018  Jakob   45      20
01-02-2018  Adomas  90      20
01-02-2018  Thomas  135     35

最好的问候,

Przemyslaw

P.S。更新

如果数据每个月都不增加怎么办?

示例输入:

Date    SalesRep    itemA   itemB
01-01-2018  Jakob   5       10
01-01-2018  Adomas  10      20
01-01-2018  Thomas  15      30
**01-02-2018    Jakob   50      30**
01-02-2018  Adomas  100     40
01-02-2018  Thomas  150     65
**01-03-2018    Jakob   50      30**
01-03-2018  Adomas  102     60
01-03-2018  Thomas  155     75

如果Jakob每月都不增加,那么您的解决方案就无法正常工作吗?我能以某种方式指定要检查的参数并仅在发生更改时减去吗?

4 个答案:

答案 0 :(得分:2)

您可以按销售代表分组并进行逐行差异。然后将数据集合并回去。

import pandas as pd

df = pd.DataFrame({
    'Date': ['01-01-2018', '01-01-2018', '01-01-2018', '01-02-2018', '01-02-2018', '01-02-2018'],
    'SalesRep': ['Jakob', 'Adomas', 'Thomas', 'Jakob', 'Adomas', 'Thomas',],
    'itemA': [5, 10, 15, 50, 100, 150],
    'itemB': [10, 20, 30, 30, 40, 65]})

df_diff = df.groupby('SalesRep').diff().fillna(0).astype(int)
df.loc[:, ['itemA', 'itemB']] = df_diff.where(df_diff, df.loc[:, ['itemA', 'itemB']])

df
# returns:
         Date SalesRep  itemA  itemB
0  01-01-2018    Jakob      5     10
1  01-01-2018   Adomas     10     20
2  01-01-2018   Thomas     15     30
3  01-02-2018    Jakob     45     20
4  01-02-2018   Adomas     90     20
5  01-02-2018   Thomas    135     35

答案 1 :(得分:1)

基本上使用fprintf(strrep([repmat('%f\t', 1, size(A, 2)) '\n'],'\t\n','\n'), A'); DataFrame.groupby。不幸的是,前几行缺少前一行,它们是diff,需要进行一些混乱的清理工作。可能有更漂亮的方法。

nan

答案 2 :(得分:1)

这是使用shift的另一种方法。它实际上是减去前一个数字。假定DataFrame已经按照正确的顺序排列(如果不是,请首先使用DataFrame.sort_values)。我认为这样比较好,因为它提供了就地单线。

df = pd.DataFrame(
    data=[
        ['01-01-2018', 'Jakob', 5, 10],
        ['01-01-2018', 'Adomas', 10, 20],
        ['01-01-2018', 'Thomas', 15, 30],
        ['01-02-2018', 'Jakob', 50, 30],
        ['01-02-2018', 'Adomas', 100, 40],
        ['01-02-2018', 'Thomas', 150, 65],
        ['01-03-2018', 'Jakob', 60, 30],
        ['01-03-2018', 'Adomas', 120, 45],
        ['01-03-2018', 'Thomas', 200, 75]
    ],
    columns=['Date', 'Sales rep', 'item A', 'item B']
)

group_by_columns = ['Sales rep']
cum_columns = ['item A', 'item B']

df[cum_columns] -= df.groupby(group_by_columns)[cum_columns].shift(1).fillna(0)

print(df)
Out:
         Date Sales rep  item A  item B
0  01-01-2018     Jakob     5.0    10.0
1  01-01-2018    Adomas    10.0    20.0
2  01-01-2018    Thomas    15.0    30.0
3  01-02-2018     Jakob    45.0    20.0
4  01-02-2018    Adomas    90.0    20.0
5  01-02-2018    Thomas   135.0    35.0
6  01-03-2018     Jakob    10.0     0.0
7  01-03-2018    Adomas    20.0     5.0
8  01-03-2018    Thomas    50.0    10.0

答案 3 :(得分:0)

这是Denziloe回答的不太普遍但更漂亮的版本:

def reverse_cumsum(series):
    series_zeroed = pd.concat([pd.Series([0]), series])
    return series_zeroed.diff()[1:]

这可以在您的示例中使用,方法是按日期排序,然后在按所需列(在您的情况下为“ SalesRep”)分组之后应用此方法。