Nhóm gấu trúc theo tổng tích lũy


94

Tôi muốn thêm cột tổng tích lũy vào khung dữ liệu Pandas của mình để:

name | day       | no
-----|-----------|----
Jack | Monday    | 10
Jack | Tuesday   | 20
Jack | Tuesday   | 10
Jack | Wednesday | 50
Jill | Monday    | 40
Jill | Wednesday | 110

trở thành:

Jack | Monday     | 10  | 10
Jack | Tuesday    | 30  | 40
Jack | Wednesday  | 50  | 90
Jill | Monday     | 40  | 40
Jill | Wednesday  | 110 | 150

Tôi đã thử nhiều cách kết hợp khác nhau df.groupbydf.agg(lambda x: cumsum(x))không có kết quả.


Bạn có thực sự chắc chắn rằng bạn muốn tổng hợp các ngày trong tuần không? Điều đó làm mất chỉ số và tổng tích lũy cũng ít có ý nghĩa hơn nếu có nhiều tuần. Thay vào đó, câu trả lời của dmitry-andreev và @vjayky sẽ tính cumsum theo chuỗi ngày cho mỗi tên. Hãy nghĩ xem điều này có thể được mở rộng như thế nào nếu cũng có cột ngày tháng để các mục nhập có thể được sắp xếp theo trước khi nhóm và tổng hợp.
Elias Hasle

Câu trả lời:


90

Điều này nên làm điều đó, cần groupby()hai lần:

df.groupby(['name', 'day']).sum() \
  .groupby(level=0).cumsum().reset_index()

Giải trình:

print(df)
   name        day   no
0  Jack     Monday   10
1  Jack    Tuesday   20
2  Jack    Tuesday   10
3  Jack  Wednesday   50
4  Jill     Monday   40
5  Jill  Wednesday  110

# sum per name/day
print( df.groupby(['name', 'day']).sum() )
                 no
name day           
Jack Monday      10
     Tuesday     30
     Wednesday   50
Jill Monday      40
      Wednesday  110

# cumulative sum per name/day
print( df.groupby(['name', 'day']).sum() \
         .groupby(level=0).cumsum() )
                 no
name day           
Jack Monday      10
     Tuesday     40
     Wednesday   90
Jill Monday      40
     Wednesday  150

Khung dữ liệu thu được từ tổng đầu tiên được lập chỉ mục theo 'name'và theo 'day'. Bạn có thể thấy nó bằng cách in

df.groupby(['name', 'day']).sum().index 

Khi tính toán tổng tích lũy, bạn muốn làm như vậy bằng cách 'name' , tương ứng với chỉ số đầu tiên (mức 0).

Cuối cùng, sử dụng reset_indexđể lặp lại các tên.

df.groupby(['name', 'day']).sum().groupby(level=0).cumsum().reset_index()

   name        day   no
0  Jack     Monday   10
1  Jack    Tuesday   40
2  Jack  Wednesday   90
3  Jill     Monday   40
4  Jill  Wednesday  150

3
Cảm ơn vì câu trả lời. Mặc dù vậy, tôi có một số truy vấn: 1. Bạn có thể vui lòng giải thích 'level = [0]' nghĩa là gì không? 2. Ngoài ra, như bạn có thể thấy, trước đây bạn đã có số hàng trong khung dữ liệu của mình và những số hàng này sẽ biến mất khi bạn thực hiện tính tổng tích lũy. Có cách nào để có chúng trở lại không?
user3694373

5
1), Số chỉ mục phải đi, vì tổng số từ nhiều hàng, như số thứ 2, 40, là 10 + 20 + 10, giá trị chỉ mục nào sẽ nhận được? 1, 2 hay 3? Vì vậy, hãy tiếp tục sử dụng namedayas multiIndex, điều này có ý nghĩa hơn ( reset_index()để lấy intchỉ mục, nếu muốn). 2), level=[0]phương tiện groupbylà hoạt động ở cấp độ đầu tiên của MultiIndex, cụ thể là cột name.
CT Zhu

Cảm ơn CT. Tôi đã hiểu điều đó sau đó và đã thử reset_index () để giải quyết vấn đề của mình. Cảm ơn vì lời giải thích chi tiết!
user3694373

4
Có một lỗi nhỏ: groupby()mặc định đầu tiên là sắp xếp các phím, vì vậy nếu bạn thêm hàng Jack-Thứ Năm ở cuối tập dữ liệu đầu vào, bạn sẽ nhận được kết quả không mong đợi. Và vì groupby()có thể làm việc với các tên cấp, tôi thấy df.groupby(['name', 'day'], sort=False).sum().groupby(by='name').cumsum().reset_index()ít khó hiểu hơn.
Nickolay

Làm thế nào để bạn đổi tên cột?
Jonathan Lam

47

Điều này hoạt động ở gấu trúc 0.16.2

In[23]: print df
        name          day   no
0      Jack       Monday    10
1      Jack      Tuesday    20
2      Jack      Tuesday    10
3      Jack    Wednesday    50
4      Jill       Monday    40
5      Jill    Wednesday   110
In[24]: df['no_cumulative'] = df.groupby(['name'])['no'].apply(lambda x: x.cumsum())
In[25]: print df
        name          day   no  no_cumulative
0      Jack       Monday    10             10
1      Jack      Tuesday    20             30
2      Jack      Tuesday    10             40
3      Jack    Wednesday    50             90
4      Jill       Monday    40             40
5      Jill    Wednesday   110            150

Hướng dẫn cách thêm nó trở lại df thực sự hữu ích. Tôi đã thử sử dụng một biến đổi, nhưng điều đó không phù hợp với cumsum ().
zerovector

2
Lưu ý rằng câu trả lời này (có vẻ tương đương với giải pháp đơn giản hơn của @vjayky ) không tổng hợp trước namedaytrước khi tính tổng tích lũy bằng name(lưu ý: có 2 hàng cho Jack + Thứ ba trong kết quả). Đây là điều làm cho nó đơn giản hơn câu trả lời của CT Zhu .
Nickolay

39

Sửa đổi câu trả lời của @ Dmitry. Điều này đơn giản hơn và hoạt động trong pandas 0.19.0:

print(df) 

 name        day   no
0  Jack     Monday   10
1  Jack    Tuesday   20
2  Jack    Tuesday   10
3  Jack  Wednesday   50
4  Jill     Monday   40
5  Jill  Wednesday  110

df['no_csum'] = df.groupby(['name'])['no'].cumsum()

print(df)
   name        day   no  no_csum
0  Jack     Monday   10       10
1  Jack    Tuesday   20       30
2  Jack    Tuesday   10       40
3  Jack  Wednesday   50       90
4  Jill     Monday   40       40
5  Jill  Wednesday  110      150

2
Đây có vẻ là giải pháp đơn giản nhất nếu bạn không cần tổng hợp hai bước , như yêu cầu trong câu hỏi.
Nickolay

Phần duy nhất tôi không đặc biệt thích là nó đã chuyển đổi kiểu int của tôi thành một float.
Chris Farr

Đây phải là câu trả lời được chấp nhận cho sự cumsum trong phần nhóm. @ChrisFarr Nó dường như không chuyển đổi thành float nữa đối với tôi kể từ gấu trúc 1.0.3.
Louis Yang

8

bạn nên sử dụng

df['cum_no'] = df.no.cumsum()

http://pandas.pydata.org/pandas-docs/version/0.19.2/generated/pandas.DataFrame.cumsum.html

Một cách khác để làm điều đó

import pandas as pd
df = pd.DataFrame({'C1' : ['a','a','a','b','b'],
           'C2' : [1,2,3,4,5]})
df['cumsum'] = df.groupby(by=['C1'])['C2'].transform(lambda x: x.cumsum())
df

nhập mô tả hình ảnh ở đây


3
Điều này tính toán tổng số hoạt động toàn cầu, thay vì tổng riêng biệt cho từng nhóm riêng biệt. Vì vậy, Jill-Monday được gán một giá trị là 130 ( 90, là tổng của tất cả các giá trị của Jack, + 40, giá trị cho Jill-Monday).
Nickolay

@Nickolay vừa thêm một câu trả lời khác, hãy cho tôi biết nếu nó hoạt động
sushmit

Tôi không chắc liệu nó có tính toán tổng số hoạt động toàn cầu theo ví dụ hàng 3 của tôi nhận giá trị là 4 hay không
sushmit

Tại sao tôi sử dụng lambda x: x.cumsum () ở đây, thay vì pandas.series.cumsum ()?
Jinhua Wang

7

Thay vì df.groupby(by=['name','day']).sum().groupby(level=[0]).cumsum() (xem ở trên), bạn cũng có thể làmdf.set_index(['name', 'day']).groupby(level=0, as_index=False).cumsum()

  • df.groupby(by=['name','day']).sum() thực ra chỉ là chuyển cả hai cột sang MultiIndex
  • as_index=False có nghĩa là bạn không cần gọi reset_index sau đó

Cảm ơn vì đã đăng bài này, nó đã giúp tôi hiểu chuyện gì đang xảy ra ở đây! Lưu ý rằng groupby().sum()không chỉ chuyển cả hai cột sang MultiIndex - nó còn tính tổng hai giá trị cho Jack + Thứ ba. Và as_index=Falsedường như không có bất kỳ tác dụng nào trong trường hợp này, vì chỉ mục đã được đặt trước groupby. Và vì đánh groupby().cumsum()số tên / ngày từ các cột của khung dữ liệu, bạn phải thêm cột số kết quả vào khung dữ liệu ban đầu (như vjayky và Dmitry đề xuất) hoặc di chuyển tên / ngày thành chỉ mục và sau đó đặt lại_index.
Nickolay

0

data.csv:

name,day,no
Jack,Monday,10
Jack,Tuesday,20
Jack,Tuesday,10
Jack,Wednesday,50
Jill,Monday,40
Jill,Wednesday,110

Mã:

import numpy as np
import pandas as pd

df = pd.read_csv('data.csv')
print(df)
df = df.groupby(['name', 'day'])['no'].sum().reset_index()
print(df)
df['cumsum'] = df.groupby(['name'])['no'].apply(lambda x: x.cumsum())
print(df)

Đầu ra:

   name        day   no
0  Jack     Monday   10
1  Jack    Tuesday   20
2  Jack    Tuesday   10
3  Jack  Wednesday   50
4  Jill     Monday   40
5  Jill  Wednesday  110
   name        day   no
0  Jack     Monday   10
1  Jack    Tuesday   30
2  Jack  Wednesday   50
3  Jill     Monday   40
4  Jill  Wednesday  110
   name        day   no  cumsum
0  Jack     Monday   10      10
1  Jack    Tuesday   30      40
2  Jack  Wednesday   50      90
3  Jill     Monday   40      40
4  Jill  Wednesday  110     150
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.