Pertimbangkan kerangka data berikut:
A B C D
0 foo one 0.162003 0.087469
1 bar one -1.156319 -1.526272
2 foo two 0.833892 -1.666304
3 bar three -2.026673 -0.322057
4 foo two 0.411452 -0.954371
5 bar two 0.765878 -0.095968
6 foo one -0.654890 0.678091
7 foo three -1.789842 -1.130922
Perintah-perintah berikut ini berfungsi:
> df.groupby('A').apply(lambda x: (x['C'] - x['D']))
> df.groupby('A').apply(lambda x: (x['C'] - x['D']).mean())
tetapi tidak satupun dari pekerjaan berikut:
> df.groupby('A').transform(lambda x: (x['C'] - x['D']))
ValueError: could not broadcast input array from shape (5) into shape (5,3)
> df.groupby('A').transform(lambda x: (x['C'] - x['D']).mean())
TypeError: cannot concatenate a non-NDFrame object
Mengapa? Contoh pada dokumentasi tampaknya menyarankan bahwa memanggil transform
grup memungkinkan seseorang untuk melakukan pemrosesan operasi baris-bijaksana:
# Note that the following suggests row-wise operation (x.mean is the column mean)
zscore = lambda x: (x - x.mean()) / x.std()
transformed = ts.groupby(key).transform(zscore)
Dengan kata lain, saya berpikir bahwa transformasi pada dasarnya adalah tipe penerapan tertentu (yang tidak agregat). Dimana saya salah
Untuk referensi, di bawah ini adalah konstruksi kerangka data asli di atas:
df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar',
'foo', 'bar', 'foo', 'foo'],
'B' : ['one', 'one', 'two', 'three',
'two', 'two', 'one', 'three'],
'C' : randn(8), 'D' : randn(8)})
transform
harus mengembalikan angka, baris, atau bentuk yang sama dengan argumen. jika itu angka maka nomor akan diatur ke semua elemen dalam grup, jika itu adalah baris, itu akan disiarkan ke semua baris dalam grup. Dalam kode Anda, fungsi lambda mengembalikan kolom yang tidak dapat disiarkan ke grup.zscore
),transform
menerima fungsi lambda yang mengasumsikan masingx
- masing adalah item dalamgroup
, dan juga mengembalikan nilai per item dalam grup. Apa yang saya lewatkan?apply
melewati seluruh df, tetapitransform
melewati setiap kolom satu per satu sebagai Seri. 2)apply
dapat mengembalikan output bentuk apa pun (skalar / Seri / DataFrame / array / list ...), sedangkantransform
harus mengembalikan urutan (Seri 1D / array / daftar) dengan panjang yang sama dengan grup. Itu sebabnya OPapply()
tidak perlutransform()
. Ini adalah pertanyaan yang bagus karena dokter tidak menjelaskan kedua perbedaan dengan jelas. (mirip dengan perbedaan antaraapply/map/applymap
, atau hal-hal lain ...)Jawaban:
Dua perbedaan utama antara
apply
dantransform
Ada dua perbedaan utama antara metode
transform
danapply
groupby.apply
secara implisit meneruskan semua kolom untuk setiap grup sebagai DataFrame ke fungsi kustom.transform
melewati setiap kolom untuk setiap grup secara individual sebagai Seri ke fungsi kustom.apply
dapat mengembalikan skalar, atau Seri atau DataFrame (atau array numpy atau daftar genap) .transform
harus mengembalikan urutan (Seri, array, atau daftar satu dimensi) dengan panjang yang sama dengan grup .Jadi,
transform
bekerja hanya pada satu seri pada satu waktu danapply
bekerja pada seluruh DataFrame sekaligus.Memeriksa fungsi kustom
Ini dapat membantu sedikit untuk memeriksa input ke fungsi kustom Anda diteruskan ke
apply
atautransform
.Contohnya
Mari kita membuat beberapa sampel data dan memeriksa grup sehingga Anda dapat melihat apa yang saya bicarakan:
Mari kita buat fungsi kustom sederhana yang mencetak jenis objek yang dilewatkan secara implisit dan kemudian menimbulkan kesalahan sehingga eksekusi dapat dihentikan.
Sekarang mari kita lewati fungsi ini ke groupby
apply
dantransform
metode untuk melihat objek apa yang diteruskan ke sana:Seperti yang Anda lihat, DataFrame dilewatkan ke
inspect
fungsi. Anda mungkin bertanya-tanya mengapa jenisnya, DataFrame, dicetak dua kali. Panda menjalankan grup pertama dua kali. Ini dilakukan untuk menentukan apakah ada cara cepat untuk menyelesaikan perhitungan atau tidak. Ini adalah detail kecil yang tidak perlu Anda khawatirkan.Sekarang, mari kita lakukan hal yang sama dengannya
transform
Itu dilewatkan Seri - objek Pandas yang sama sekali berbeda.
Jadi,
transform
hanya diperbolehkan bekerja dengan satu Seri pada satu waktu. Bukan tidak mungkin untuk bertindak pada dua kolom secara bersamaan. Jadi, jika kita mencoba dan mengurangi koloma
darib
dalam fungsi kustom kita, kita akan mendapatkan kesalahantransform
. Lihat di bawah:Kami mendapatkan KeyError karena panda berusaha menemukan indeks Seri
a
yang tidak ada. Anda dapat menyelesaikan operasi iniapply
karena memiliki seluruh DataFrame:Outputnya adalah Seri dan sedikit membingungkan karena indeks asli disimpan, tetapi kami memiliki akses ke semua kolom.
Menampilkan objek panda yang dilewati
Ini dapat membantu lebih banyak lagi untuk menampilkan seluruh objek panda dalam fungsi kustom, sehingga Anda dapat melihat dengan tepat apa yang Anda operasikan. Anda dapat menggunakan
print
pernyataan dengan saya ingin menggunakandisplay
fungsi dariIPython.display
modul sehingga DataFrames dapat dihasilkan dengan baik dalam HTML di notebook jupyter:Tangkapan layar:
Transform harus mengembalikan urutan dimensi tunggal dengan ukuran yang sama dengan grup
Perbedaan lainnya adalah bahwa
transform
harus mengembalikan urutan dimensi tunggal dengan ukuran yang sama dengan grup. Dalam contoh khusus ini, setiap grup memiliki dua baris, jaditransform
harus mengembalikan urutan dua baris. Jika tidak maka kesalahan muncul:Pesan kesalahan sebenarnya tidak deskriptif tentang masalahnya. Anda harus mengembalikan urutan dengan panjang yang sama dengan grup. Jadi, fungsi seperti ini akan berfungsi:
Mengembalikan objek skalar tunggal juga berfungsi untuk
transform
Jika Anda mengembalikan hanya satu skalar dari fungsi khusus Anda, maka
transform
akan menggunakannya untuk setiap baris dalam grup:sumber
np
tak terdefinisi. Saya menganggap pemula akan menghargai jika Anda memasukkanimport numpy as np
ke dalam jawaban Anda.Karena saya juga merasa bingung dengan
.transform
operasi vs..apply
Saya menemukan beberapa jawaban yang menjelaskan masalah ini. Misalnya jawaban ini sangat membantu.Takeout saya sejauh ini adalah yang
.transform
akan bekerja (atau menangani) denganSeries
(kolom) terpisah satu sama lain . Apa artinya ini dalam dua panggilan terakhir Anda:Anda diminta
.transform
untuk mengambil nilai dari dua kolom dan 'itu' sebenarnya tidak 'melihat' keduanya pada saat yang sama (bisa dikatakan).transform
akan melihat kolom dataframe satu per satu dan mengembalikan seri (atau grup seri) yang 'terbuat' dari skalar yang berulanglen(input_column)
kali.Jadi skalar ini, yang harus digunakan
.transform
untuk membuatSeries
adalah hasil dari beberapa fungsi reduksi yang diterapkan pada inputSeries
(dan hanya pada SATU seri / kolom pada suatu waktu).Pertimbangkan contoh ini (pada kerangka data Anda):
akan menghasilkan:
Yang persis sama seperti jika Anda menggunakannya hanya pada satu kolom pada satu waktu:
menghasilkan:
Perhatikan bahwa
.apply
dalam contoh terakhir (df.groupby('A')['C'].apply(zscore)
) akan bekerja dengan cara yang persis sama, tetapi akan gagal jika Anda mencoba menggunakannya pada dataframe:memberikan kesalahan:
Jadi di mana lagi yang
.transform
berguna? Kasus paling sederhana adalah mencoba untuk menetapkan hasil fungsi reduksi kembali ke kerangka data asli.menghasilkan:
Mencoba sama dengan
.apply
akan memberikanNaNs
disum_C
. Karena.apply
akan mengembalikan dikurangiSeries
, yang tidak tahu bagaimana menyiarkan kembali:memberi:
Ada juga kasus ketika
.transform
digunakan untuk memfilter data:Saya harap ini menambah sedikit kejelasan.
sumber
.transform()
dapat juga digunakan untuk mengisi nilai yang hilang. Terutama jika Anda ingin menyiarkan rata-rata grup atau statistik grup keNaN
nilai di grup itu. Sayangnya, dokumentasi panda juga tidak membantu saya..groupby().filter()
melakukan hal yang sama. Terima kasih atas penjelasan Anda,.apply()
dan.transform()
membuat saya sangat bingung.df.groupby().transform()
tidak dapat bekerja untuk sub grup df, saya selalu mendapatkan kesalahanValueError: transform must return a scalar value for each group
karenatransform
melihat kolom satu per satuSaya akan menggunakan cuplikan yang sangat sederhana untuk menggambarkan perbedaan:
DataFrame terlihat seperti ini:
Ada 3 ID pelanggan dalam tabel ini, masing-masing pelanggan melakukan tiga transaksi dan membayar 1,2,3 dolar setiap kali.
Sekarang, saya ingin menemukan pembayaran minimum yang dilakukan oleh setiap pelanggan. Ada dua cara untuk melakukannya:
Menggunakan
apply
:grouping.min ()
Pengembalian terlihat seperti ini:
Menggunakan
transform
:pengelompokan.transformasi (mnt)
Pengembalian terlihat seperti ini:
Kedua metode mengembalikan
Series
objek, tetapilength
yang pertama adalah 3 danlength
yang kedua adalah 9.Jika Anda ingin menjawab
What is the minimum price paid by each customer
, makaapply
metode yang paling cocok untuk dipilih.Jika Anda ingin menjawab
What is the difference between the amount paid for each transaction vs the minimum payment
, maka Anda ingin menggunakantransform
, karena:Apply
tidak bekerja di sini hanya karena mengembalikan Seri ukuran 3, tetapi panjang df asli adalah 9. Anda tidak dapat mengintegrasikannya kembali ke df asli dengan mudah.sumber
seperti
atau
sumber