The docs menunjukkan bagaimana menerapkan beberapa fungsi pada objek groupby pada waktu menggunakan dict dengan nama kolom output sebagai kunci:
In [563]: grouped['D'].agg({'result1' : np.sum,
.....: 'result2' : np.mean})
.....:
Out[563]:
result2 result1
A
bar -0.579846 -1.739537
foo -0.280588 -1.402938
Namun, ini hanya berfungsi pada objek Series group oleh. Dan ketika sebuah dikt sama dilewatkan ke grup oleh DataFrame, itu mengharapkan kunci untuk menjadi nama kolom yang fungsi akan diterapkan.
Yang ingin saya lakukan adalah menerapkan beberapa fungsi ke beberapa kolom (tetapi kolom tertentu akan dioperasikan beberapa kali). Juga, beberapa fungsi akan tergantung pada kolom lain di objek groupby (seperti fungsi sumif). Solusi saya saat ini adalah pergi kolom demi kolom, dan melakukan sesuatu seperti kode di atas, menggunakan lambdas untuk fungsi yang bergantung pada baris lain. Tapi ini butuh waktu lama, (saya pikir butuh waktu lama untuk beralih melalui objek grup). Saya harus mengubahnya sehingga saya mengulangi seluruh objek grup dengan sekali jalan, tapi saya ingin tahu apakah ada cara panda untuk melakukan ini dengan agak bersih.
Misalnya, saya sudah mencoba sesuatu seperti
grouped.agg({'C_sum' : lambda x: x['C'].sum(),
'C_std': lambda x: x['C'].std(),
'D_sum' : lambda x: x['D'].sum()},
'D_sumifC3': lambda x: x['D'][x['C'] == 3].sum(), ...)
tapi seperti yang diharapkan saya mendapatkan KeyError (karena kunci harus berupa kolom jika agg
dipanggil dari DataFrame).
Apakah ada cara dibangun untuk melakukan apa yang ingin saya lakukan, atau kemungkinan bahwa fungsi ini dapat ditambahkan, atau apakah saya hanya perlu mengulang melalui grup secara manual?
Terima kasih
sumber
Jawaban:
Bagian kedua dari jawaban yang saat ini diterima sudah usang dan memiliki dua penghinaan. Pertama dan paling penting, Anda tidak bisa lagi meneruskan kamus kamus ke
agg
metode groupby. Kedua, jangan pernah gunakan.ix
.Jika Anda ingin bekerja dengan dua kolom terpisah pada saat yang sama saya akan menyarankan menggunakan
apply
metode yang secara implisit meneruskan DataFrame ke fungsi yang diterapkan. Mari kita gunakan kerangka data yang sama dengan yang ada di atasKamus yang dipetakan dari nama kolom ke fungsi agregasi masih merupakan cara yang sangat baik untuk melakukan agregasi.
Jika Anda tidak menyukai nama kolom lambda yang jelek itu, Anda dapat menggunakan fungsi normal dan memberikan nama khusus ke
__name__
atribut khusus seperti ini:Menggunakan
apply
dan mengembalikan SeriSekarang, jika Anda memiliki beberapa kolom yang perlu berinteraksi bersama maka Anda tidak dapat menggunakan
agg
, yang secara implisit meneruskan Seri ke fungsi agregasi. Saat menggunakanapply
seluruh grup sebagai DataFrame masuk ke fungsi.Saya sarankan membuat fungsi kustom tunggal yang mengembalikan Seri semua agregasi. Gunakan indeks Seri sebagai label untuk kolom baru:
Jika Anda jatuh cinta dengan MultiIndexes, Anda masih dapat mengembalikan Seri dengan yang seperti ini:
sumber
a
dalam kelompok0
seharusnya tidak0.418500 + 0.446069 = 0.864569
? Hal yang sama berlaku untuk sel-sel lain, jumlahnya tampaknya tidak bertambah. Mungkinkah kerangka data dasar yang sedikit berbeda digunakan dalam contoh-contoh selanjutnya?Untuk bagian pertama, Anda dapat melewati dict nama kolom untuk kunci dan daftar fungsi untuk nilai:
PEMBARUAN 1:
Karena fungsi agregat bekerja pada Seri, referensi ke nama kolom lainnya hilang. Untuk menyiasatinya, Anda dapat mereferensikan dataframe lengkap dan mengindeksnya menggunakan indeks grup dalam fungsi lambda.
Berikut ini solusinya:
Di sini, kolom 'D' yang dihasilkan terdiri dari nilai-nilai 'E' yang dijumlahkan.
PEMBARUAN 2:
Inilah metode yang saya pikir akan melakukan semua yang Anda minta. Pertama buat fungsi lambda khusus. Di bawah, g referensi grup. Saat menjumlahkan, g akan menjadi sebuah Seri. Lulus
g.index
untukdf.ix[]
memilih grup saat ini dari df. Saya kemudian menguji apakah kolom C kurang dari 0,5. Seri boolean yang dikembalikan dilewatkan keg[]
yang memilih hanya baris yang memenuhi kriteria.sumber
{funcname: func}
sebagai nilai alih-alih daftar untuk menjaga nama kustom saya. Tetapi dalam kedua kasus saya tidak bisa melewatilambda
yang menggunakan kolom lain (seperti dilambda x: x['D'][x['C'] < 3].sum()
atas: "KeyError: 'D'"). Adakah ide jika itu mungkin?KeyError: 'D'
df['A'].ix[g.index][df['C'] < 0].sum()
. Ini mulai menjadi sangat berantakan, meskipun - saya pikir untuk pengacakan manual keterbacaan mungkin lebih disukai, ditambah saya tidak yakin ada cara untuk memberikan nama pilihan saya dalamagg
argumen (bukan<lambda>
). Saya akan mengulurkan harapan bahwa seseorang mungkin tahu cara yang lebih mudah ...{'D': {'my name':lambda function}}
dan itu akan membuat kunci dict bagian dalam nama kolom.Sebagai alternatif (sebagian besar pada estetika) untuk jawaban Ted Petrou, saya menemukan saya lebih suka daftar yang sedikit lebih kompak. Tolong jangan mempertimbangkan untuk menerimanya, itu hanya komentar yang jauh lebih rinci tentang jawaban Ted, ditambah kode / data. Python / panda bukan yang pertama / terbaik saya, tetapi saya menemukan ini untuk dibaca dengan baik:
Saya merasa lebih mirip
dplyr
pipa dandata.table
perintah dirantai. Bukan untuk mengatakan mereka lebih baik, hanya lebih akrab bagi saya. (Saya tentu mengenali kekuatan dan, bagi banyak orang, preferensi untuk menggunakandef
fungsi yang lebih formal untuk jenis operasi ini. Ini hanya sebuah alternatif, belum tentu lebih baik.)Saya menghasilkan data dengan cara yang sama seperti Ted, saya akan menambahkan benih untuk reproduktifitas.
sumber
Pandas >= 0.25.0
, bernama agregasiSejak versi panda
0.25.0
atau lebih tinggi, kami menjauh dari agregasi dan penamaan ulang berdasarkan kamus, dan bergerak menuju agregasi bernama yang menerima atuple
. Sekarang kita dapat secara bersamaan mengumpulkan + mengubah nama menjadi nama kolom yang lebih informatif:Contoh :
Terapkan
GroupBy.agg
dengan agregasi bernama:sumber
Baru dalam versi 0.25.0.
Untuk mendukung agregasi khusus kolom dengan kontrol atas nama kolom output, panda menerima sintaks khusus di GroupBy.agg () , yang dikenal sebagai "agregasi bernama" , di mana
panda.NamedAgg hanyalah sebuah namedTuple. Tuple polos juga diizinkan.
Argumen kata kunci tambahan tidak diteruskan ke fungsi agregasi. Hanya pasangan (kolom, aggfunc) yang harus dilewatkan sebagai ** kwargs. Jika fungsi agregasi Anda memerlukan argumen tambahan, terapkan sebagian dengan functools.partial ().
Agregasi yang dinamai juga berlaku untuk grup Agregasi oleh agregasi. Dalam hal ini tidak ada pemilihan kolom, jadi nilainya hanya fungsi.
sumber
Jawaban Ted luar biasa. Saya akhirnya menggunakan versi yang lebih kecil kalau-kalau ada yang tertarik. Berguna saat Anda mencari satu agregasi yang bergantung pada nilai dari beberapa kolom:
buat dataframe
pengelompokan dan agregasi dengan berlaku (menggunakan beberapa kolom)
pengelompokan dan agregasi dengan agregat (menggunakan beberapa kolom)
Saya suka pendekatan ini karena saya masih bisa menggunakan agregat. Mungkin orang akan memberi tahu saya mengapa pendaftaran diperlukan untuk mendapatkan beberapa kolom saat melakukan agregasi pada grup.
Tampaknya sudah jelas sekarang, tetapi selama Anda tidak memilih kolom yang diinginkan langsung setelah grup oleh , Anda akan memiliki akses ke semua kolom dari kerangka data dari dalam fungsi agregasi Anda.
hanya akses ke kolom yang dipilih
akses ke semua kolom karena seleksi adalah keajaiban
atau serupa
Saya harap ini membantu.
sumber