Saya memiliki kerangka data tempat beberapa sel berisi daftar beberapa nilai. Daripada menyimpan beberapa nilai dalam sel, saya ingin memperluas kerangka data sehingga setiap item dalam daftar mendapatkan barisnya sendiri (dengan nilai yang sama di semua kolom lainnya). Jadi jika saya punya:
import pandas as pd
import numpy as np
df = pd.DataFrame(
{'trial_num': [1, 2, 3, 1, 2, 3],
'subject': [1, 1, 1, 2, 2, 2],
'samples': [list(np.random.randn(3).round(2)) for i in range(6)]
}
)
df
Out[10]:
samples subject trial_num
0 [0.57, -0.83, 1.44] 1 1
1 [-0.01, 1.13, 0.36] 1 2
2 [1.18, -1.46, -0.94] 1 3
3 [-0.08, -4.22, -2.05] 2 1
4 [0.72, 0.79, 0.53] 2 2
5 [0.4, -0.32, -0.13] 2 3
Bagaimana saya mengonversi ke bentuk panjang, misalnya:
subject trial_num sample sample_num
0 1 1 0.57 0
1 1 1 -0.83 1
2 1 1 1.44 2
3 1 2 -0.01 0
4 1 2 1.13 1
5 1 2 0.36 2
6 1 3 1.18 0
# etc.
Indeks tidak penting, tidak apa-apa untuk mengatur kolom yang ada sebagai indeks dan pemesanan akhir tidak penting.
df.explode('samples')
untuk menyelesaikan ini.explode
hanya dapat mendukung peledakan satu kolom untuk saat ini.Jawaban:
Hasil:
PS di sini Anda dapat menemukan solusi yang sedikit lebih umum
UPDATE: beberapa penjelasan: IMO cara termudah untuk memahami kode ini adalah dengan mencoba menjalankannya langkah demi langkah:
pada baris berikut kami mengulangi nilai dalam satu kolom
N
kali di manaN
- adalah panjang daftar yang sesuai:ini dapat digeneralisasi untuk semua kolom, yang berisi nilai skalar:
menggunakan
np.concatenate()
kita dapat meratakan semua nilai dilist
kolom (samples
) dan mendapatkan vektor 1D:menyusun semua ini:
menggunakan
pd.DataFrame()[df.columns]
akan menjamin bahwa kami memilih kolom dalam urutan asli ...sumber
lst_col
seluruhnya; untuk menjaga baris-baris ini dan mengisilst_col
dengannp.nan
, Anda bisa melakukannyadf[lst_col] = df[lst_col].apply(lambda x: x if len(x) > 0 else [np.nan])
sebelum menggunakan metode ini. Jelas.mask
tidak akan mengembalikan daftar, karenanya.apply
.Sedikit lebih lama dari yang saya harapkan:
Jika Anda ingin indeks berurutan, Anda dapat menerapkannya
reset_index(drop=True)
pada hasilnya.perbarui :
sumber
df.apply(lambda x: pd.Series(x['samples']),axis=1)
dengandf.samples.apply(pd.Series)
.df.explode()
seperti yang ditunjukkan di sini.Panda> = 0,25
Metode Series dan DataFrame menentukan
.explode()
metode yang meledakkan daftar menjadi baris terpisah. Lihat bagian dokumen pada Meledak kolom seperti daftar .Perhatikan bahwa ini juga menangani kolom campuran dari daftar dan skalar, serta daftar kosong dan NaN secara tepat (ini adalah kelemahan dari
repeat
solusi berbasis).Namun, Anda harus mencatat bahwa
explode
hanya berfungsi pada satu kolom (untuk saat ini).PS: jika Anda ingin meledakkan kolom string , Anda harus membelah pemisah terlebih dahulu, kemudian gunakan
explode
. Lihat ini (sangat banyak) terkait jawaban oleh saya.sumber
Anda juga dapat menggunakan
pd.concat
danpd.melt
untuk ini:terakhir, jika perlu, Anda dapat mengurutkan berdasarkan yang pertama tiga kolom pertama.
sumber
Mencoba untuk bekerja melalui solusi Roman Pekar langkah demi langkah untuk memahaminya dengan lebih baik, saya datang dengan solusi saya sendiri, yang digunakan
melt
untuk menghindari beberapa susun dan pengaturan ulang indeks yang membingungkan. Saya tidak bisa mengatakan bahwa itu jelas solusi yang lebih jelas:Keluaran (jelas kami dapat menjatuhkan kolom sampel asli sekarang):
sumber
Bagi mereka yang mencari versi jawaban Roman Pekar yang menghindari penamaan kolom manual:
sumber
Saya menemukan cara termudah adalah:
samples
kolom menjadi DataFrameDitunjukkan di sini:
Perlu dicatat bahwa ini mungkin hanya berhasil karena setiap percobaan memiliki jumlah sampel yang sama (3). Sesuatu yang lebih pintar mungkin diperlukan untuk uji coba ukuran sampel yang berbeda.
sumber
Jawaban yang sangat terlambat tetapi saya ingin menambahkan ini:
Solusi cepat menggunakan vanilla Python yang juga menangani
sample_num
kolom dalam contoh OP. Pada dataset besar saya sendiri dengan lebih dari 10 juta baris dan hasil dengan 28 juta baris ini hanya membutuhkan waktu sekitar 38 detik. Solusi yang diterima benar-benar rusak dengan jumlah data dan mengarahmemory error
pada sistem saya yang memiliki 128GB RAM.sumber
Juga sangat terlambat, tetapi di sini ada jawaban dari Karvy1 yang bekerja dengan baik bagi saya jika Anda tidak memiliki panda> = versi 0.25: https://stackoverflow.com/a/52511166/10740287
Untuk contoh di atas, Anda dapat menulis:
Tes kecepatan:
1,33 ms ± 74,8 µs per loop (rata-rata ± st. Dev dari 7 berjalan, masing-masing 1000 loop)
4,9 ms ± 189 µs per loop (rata-rata ± st. Dev dari 7 run, masing-masing 100 loop)
1,38 ms ± 25 µs per loop (rata-rata ± st. Dev dari 7 run, masing-masing 1000 loop)
sumber
Coba ini dalam panda> = versi 0.25
sumber
.str.split(',')
karenaPrices
sudah daftar.