การรวมคอลัมน์เดียวกันหลายรายการโดยใช้ pandas GroupBy.agg ()


130

มีแพนด้าในตัวเพื่อใช้ฟังก์ชันการรวมที่แตกต่างกันสองฟังก์ชันf1, f2กับคอลัมน์เดียวกันdf["returns"]โดยไม่ต้องเรียกagg()หลายครั้งหรือไม่?

ตัวอย่างดาต้าเฟรม:

import pandas as pd
import datetime as dt

pd.np.random.seed(0)
df = pd.DataFrame({
         "date"    :  [dt.date(2012, x, 1) for x in range(1, 11)], 
         "returns" :  0.05 * np.random.randn(10), 
         "dummy"   :  np.repeat(1, 10)
}) 

ผิดทางวากยสัมพันธ์ แต่ถูกต้องโดยสังหรณ์ใจวิธีที่จะทำคือ:

# Assume `f1` and `f2` are defined for aggregating.
df.groupby("dummy").agg({"returns": f1, "returns": f2})

เห็นได้ชัดว่า Python ไม่อนุญาตให้มีคีย์ที่ซ้ำกัน มีลักษณะอื่นในการแสดงข้อมูลเข้าagg()หรือไม่? บางทีรายการสิ่งที่เพิ่มขึ้น[(column, function)]จะทำงานได้ดีขึ้นเพื่ออนุญาตให้ใช้ฟังก์ชันหลายอย่างกับคอลัมน์เดียวกัน แต่agg()ดูเหมือนว่าจะยอมรับเฉพาะพจนานุกรมเท่านั้น

มีวิธีแก้ปัญหาสำหรับสิ่งนี้นอกเหนือจากการกำหนดฟังก์ชันเสริมที่ใช้เพียงฟังก์ชันทั้งสองภายในหรือไม่? (วิธีนี้จะทำงานร่วมกับการรวมได้อย่างไร)


ที่เกี่ยวข้อง - การรวมตัวในหมีแพนด้า
jezrael

2
ตั้งแต่ 0.25 เป็นต้นไป pandas มีไวยากรณ์ที่ใช้งานง่ายมากขึ้นสำหรับการรวมหลายรายการรวมถึงการเปลี่ยนชื่อคอลัมน์เอาต์พุต ดูเอกสารเกี่ยวกับการรวมชื่อ
cs95

FYI คำถามนี้ถูกถามกลับกับแพนด้า 0.8.x ใน 9/2555
smci

1
FYI คำตอบที่ยอมรับก็เลิกใช้เช่นกัน - อย่าส่ง agg () คำสั่งของ dict
cs95

@ cs95: ฉันรู้ว่ามันเลิกใช้แล้วฉันกำลังบอกว่า SO กำลังเกลื่อนไปด้วยโซลูชันเก่า ๆ จากเวอร์ชันเก่า SO ไม่มีวิธีการทำเครื่องหมาย - นอกเหนือจากความคิดเห็น
smci

คำตอบ:


160

คุณสามารถส่งผ่านฟังก์ชั่นเป็นรายการ:

In [20]: df.groupby("dummy").agg({"returns": [np.mean, np.sum]})
Out[20]:         
           mean       sum
dummy                    
1      0.036901  0.369012

หรือเป็นพจนานุกรม:

In [21]: df.groupby('dummy').agg({'returns':
                                  {'Mean': np.mean, 'Sum': np.sum}})
Out[21]: 
        returns          
           Mean       Sum
dummy                    
1      0.036901  0.369012

5
มีวิธีระบุชื่อคอลัมน์ผลลัพธ์หรือไม่?
เบ็น

3
@ เบ็นฉันคิดว่าคุณต้องใช้ชื่อใหม่ในภายหลัง ตัวอย่างโดย Tom Augspurger (ดูเซลล์ 25)
Stewbaca

1
@ เบ็น: ฉันได้เพิ่มตัวอย่าง
bmu

10
@sparc_spread ผ่านฟังก์ชั่นหลายรายการจะอธิบายได้ดีในเอกสารแพนด้า การเปลี่ยนชื่อและการส่งผ่านฟังก์ชันต่างๆเป็นพจนานุกรมจะถูกเลิกใช้งานในเวอร์ชันอนาคตของแพนด้า โดยมีรายละเอียดในการเข้าสู่ระบบ 0.20 การเปลี่ยนแปลงซึ่งผมยังสรุปที่อื่น ๆ บน SO
joelostblom

3
มีการกล่าวไปแล้ว แต่การใช้พจนานุกรมสำหรับการเปลี่ยนชื่อคอลัมน์ผลลัพธ์จากอายุจะถูกเลิกใช้ คุณสามารถระบุรายการสิ่งที่เพิ่มขึ้นแทนได้ ดูคำตอบนี้
cs95

103

TLDR; Pandas groupby.aggมีไวยากรณ์ใหม่ที่ง่ายกว่าสำหรับการระบุ (1) การรวมในหลายคอลัมน์และ (2) การรวมหลายรายการในคอลัมน์ ดังนั้นเพื่อทำสิ่งนี้สำหรับแพนด้า> = 0.25ให้ใช้

df.groupby('dummy').agg(Mean=('returns', 'mean'), Sum=('returns', 'sum'))

           Mean       Sum
dummy                    
1      0.036901  0.369012

หรือ

df.groupby('dummy')['returns'].agg(Mean='mean', Sum='sum')

           Mean       Sum
dummy                    
1      0.036901  0.369012

หมีแพนด้า> = 0.25: การรวมชื่อ

Pandas ได้เปลี่ยนพฤติกรรมของGroupBy.aggการใช้ไวยากรณ์ที่ใช้งานง่ายมากขึ้นสำหรับการระบุการรวมชื่อ ดูส่วน 0.25 เอกสารเกี่ยวกับการเพิ่มประสิทธิภาพเช่นเดียวกับปัญหาที่เกี่ยวข้อง GitHub GH18366และGH26512

จากเอกสารประกอบ

เพื่อสนับสนุนการรวมเฉพาะคอลัมน์ด้วยการควบคุมชื่อคอลัมน์เอาต์พุตแพนด้ายอมรับไวยากรณ์พิเศษในที่GroupBy.agg()เรียกว่า“ การรวมชื่อ” โดยที่

  • คีย์เวิร์ดคือชื่อคอลัมน์เอาต์พุต
  • ค่าคือสิ่งที่มีองค์ประกอบแรกคือคอลัมน์ที่จะเลือกและองค์ประกอบที่สองคือการรวมเพื่อใช้กับคอลัมน์นั้น Pandas ให้แพนด้าชื่อ NamedAgg พร้อมฟิลด์ ['column', 'aggfunc'] เพื่อให้ชัดเจนขึ้นว่าอาร์กิวเมนต์คืออะไร ตามปกติการรวมอาจเป็นนามแฝงที่เรียกได้หรือสตริง

ตอนนี้คุณสามารถส่งทูเพิลผ่านอาร์กิวเมนต์คำหลักได้ tuples เป็นไปตามรูปแบบของ(<colName>, <aggFunc>).

import pandas as pd

pd.__version__                                                                                                                            
# '0.25.0.dev0+840.g989f912ee'

# Setup
df = pd.DataFrame({'kind': ['cat', 'dog', 'cat', 'dog'],
                   'height': [9.1, 6.0, 9.5, 34.0],
                   'weight': [7.9, 7.5, 9.9, 198.0]
})

df.groupby('kind').agg(
    max_height=('height', 'max'), min_weight=('weight', 'min'),)

      max_height  min_weight
kind                        
cat          9.5         7.9
dog         34.0         7.5

หรือคุณสามารถใช้pd.NamedAgg(โดยพื้นฐานแล้วชื่อทูเพิล) ซึ่งทำให้สิ่งต่างๆชัดเจนยิ่งขึ้น

df.groupby('kind').agg(
    max_height=pd.NamedAgg(column='height', aggfunc='max'), 
    min_weight=pd.NamedAgg(column='weight', aggfunc='min')
)

      max_height  min_weight
kind                        
cat          9.5         7.9
dog         34.0         7.5

มันง่ายกว่าสำหรับ Series เพียงแค่ส่ง aggfunc ไปยังอาร์กิวเมนต์คำหลัก

df.groupby('kind')['height'].agg(max_height='max', min_height='min')    

      max_height  min_height
kind                        
cat          9.5         9.1
dog         34.0         6.0       

สุดท้ายหากชื่อคอลัมน์ของคุณไม่ใช่ตัวระบุ python ที่ถูกต้องให้ใช้พจนานุกรมพร้อมการคลายแพ็ก:

df.groupby('kind')['height'].agg(**{'max height': 'max', ...})

นุ่น <0.25

ในเวอร์ชันล่าสุดของแพนด้าที่นำหน้าไม่เกิน 0.24 หากใช้พจนานุกรมเพื่อระบุชื่อคอลัมน์สำหรับเอาต์พุตการรวมคุณจะได้รับFutureWarning:

df.groupby('dummy').agg({'returns': {'Mean': 'mean', 'Sum': 'sum'}})
# FutureWarning: using a dict with renaming is deprecated and will be removed 
# in a future version

การใช้พจนานุกรมเพื่อเปลี่ยนชื่อคอลัมน์เลิกใช้แล้วใน v0.20 ในเวอร์ชันล่าสุดของแพนด้าสามารถระบุได้ง่ายขึ้นโดยการส่งรายการสิ่งที่เพิ่มขึ้น หากระบุฟังก์ชันด้วยวิธีนี้จำเป็นต้องระบุฟังก์ชันทั้งหมดสำหรับคอลัมน์นั้นเป็นคู่ของคู่ (ชื่อฟังก์ชัน)

df.groupby("dummy").agg({'returns': [('op1', 'sum'), ('op2', 'mean')]})

        returns          
            op1       op2
dummy                    
1      0.328953  0.032895

หรือ,

df.groupby("dummy")['returns'].agg([('op1', 'sum'), ('op2', 'mean')])

            op1       op2
dummy                    
1      0.328953  0.032895

4
นี่ควรเป็นคำตอบอันดับต้น ๆ เนื่องจากการใช้โซลูชันที่ชัดเจนและสะอาดยิ่งขึ้นโดยใช้อินเทอร์เฟซเวอร์ชันใหม่กว่า
NKSHELL

ตัวอย่างที่ใช้สำหรับการรวมชื่อไม่ได้ช่วยแก้ปัญหาเดิมของการใช้การรวมหลายรายการในคอลัมน์เดียวกัน ตัวอย่างเช่นคุณสามารถรวมค่าต่ำสุดและสูงสุดสำหรับความสูงโดยไม่ต้องย่อยชุดแรกสำหรับdf.groupby('kind')['height']?
ผู้ชนะ

1
@victor ฉันเพิ่ม TLDR ที่ด้านบนของคำตอบที่ตอบคำถามโดยตรง และคำตอบสำหรับคำถามที่สองของคุณคือใช่โปรดดูการแก้ไขคำตอบของฉัน
cs95

รหัสทั่วไปเพิ่มเติมสำหรับตัวอย่างสุดท้ายของคำตอบ> = 0.25 ของคุณเพื่อจัดการการรวมคอลัมน์หลายคอลัมน์เช่นนี้จะดีมาก df.groupby("kind").agg(**{ 'max height': pd.NamedAgg(column='height', aggfunc=max), 'min weight': pd.NamedAgg(column='weight', aggfunc=min) })
Onur Ece

6

สิ่งที่ต้องการทำงานนี้:

In [7]: df.groupby('dummy').returns.agg({'func1' : lambda x: x.sum(), 'func2' : lambda x: x.prod()})
Out[7]: 
              func2     func1
dummy                        
1     -4.263768e-16 -0.188565

2
ไม่สิ่งนี้ใช้ไม่ได้ หากคุณดูที่สตริง doc เพราะaggregateระบุอย่างชัดเจนว่าเมื่อdictส่งผ่านคีย์จะต้องเป็นชื่อคอลัมน์ ดังนั้นตัวอย่างของคุณอาจเป็นสิ่งที่คุณพิมพ์โดยไม่ได้ตรวจสอบข้อผิดพลาดนี้หรือมิฉะนั้น Pandas จะทำลายเอกสารของตัวเองที่นี่
ely

N / MI ไม่เห็นการโทรพิเศษที่returnsนั่น นี่คือเวอร์ชันรวมของ Series? ฉันต้องการทำเวอร์ชันรวมของ DataFrame และต้องการใช้การรวมที่แตกต่างกันหลาย ๆ คอลัมน์พร้อมกัน
ely

1
ลองสิ่งนี้: df.groupby ('dummy'). agg ({'return': {'func1': lambda x: x.sum (), 'func2': lambda x: x.mean ()}})
Chang เธอ

ทำให้เกิดข้อผิดพลาดในการยืนยันโดยไม่มีข้อความ จากรูปลักษณ์ของโค้ด (pandas.core.internals.py, บรรทัด 406-408, เวอร์ชัน 0.7.3) ดูเหมือนว่าจะทำการตรวจสอบในตอนท้ายเพื่อให้แน่ใจว่าจะไม่ส่งคืนคอลัมน์มากกว่าที่มีคีย์อยู่ในตัวแรก ชั้นของพจนานุกรมการรวม
ely

ทำงานได้ดีกับต้นแบบ คุณต้องการลองอัปเดตไหม
Chang She
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.