Sebagai pengguna dengan R
dan python
, saya telah melihat jenis pertanyaan ini beberapa kali.
Di R, mereka memiliki fungsi bawaan dari paket yang tidyr
dipanggil unnest
. Namun di Python
( pandas
) tidak ada fungsi bawaan untuk jenis pertanyaan ini.
Saya tahu object
kolom type
selalu membuat data sulit untuk diubah dengan pandas
fungsi '. Ketika saya menerima data seperti ini, hal pertama yang terlintas di benak saya adalah 'meratakan' atau mengosongkan kolom.
Saya menggunakan pandas
dan python
fungsi untuk jenis pertanyaan ini. Jika Anda khawatir tentang kecepatan solusi di atas, periksa jawaban pengguna3483203, karena dia menggunakan numpy
dan sebagian besar waktu numpy
lebih cepat. Saya merekomendasikan Cpython
dan numba
jika kecepatan penting dalam kasus Anda.
Metode 0 [pandas> = 0,25]
Mulai dari panda 0,25 , jika Anda hanya perlu meledakkan satu kolom, Anda dapat menggunakan explode
fungsi:
df.explode('B')
A B
0 1 1
1 1 2
0 2 1
1 2 2
Metode 1
apply + pd.Series
(mudah dipahami tetapi dalam hal kinerja tidak disarankan.)
df.set_index('A').B.apply(pd.Series).stack().reset_index(level=0).rename(columns={0:'B'})
Out[463]:
A B
0 1 1
1 1 2
0 2 1
1 2 2
Metode 2
Menggunakan repeat
dengan DataFrame
konstruktor, buat ulang kerangka data Anda (bagus dalam kinerja, tidak bagus di banyak kolom)
df=pd.DataFrame({'A':df.A.repeat(df.B.str.len()),'B':np.concatenate(df.B.values)})
df
Out[465]:
A B
0 1 1
0 1 2
1 2 1
1 2 2
Metode 2.1
misalnya selain A kita memiliki A.1 ..... An Jika kita masih menggunakan metode ( Metode 2 ) di atas sulit bagi kita untuk membuat ulang kolom satu per satu.
Solusi: join
atau merge
dengan index
setelah 'tidak ada' kolom tunggal
s=pd.DataFrame({'B':np.concatenate(df.B.values)},index=df.index.repeat(df.B.str.len()))
s.join(df.drop('B',1),how='left')
Out[477]:
B A
0 1 1
0 2 1
1 1 2
1 2 2
Jika Anda ingin urutan kolom sama persis seperti sebelumnya, tambahkan reindex
di bagian akhir.
s.join(df.drop('B',1),how='left').reindex(columns=df.columns)
Metode 3
membuat ulang filelist
pd.DataFrame([[x] + [z] for x, y in df.values for z in y],columns=df.columns)
Out[488]:
A B
0 1 1
1 1 2
2 2 1
3 2 2
Jika lebih dari dua kolom, gunakan
s=pd.DataFrame([[x] + [z] for x, y in zip(df.index,df.B) for z in y])
s.merge(df,left_on=0,right_index=True)
Out[491]:
0 1 A B
0 0 1 1 [1, 2]
1 0 2 1 [1, 2]
2 1 1 2 [1, 2]
3 1 2 2 [1, 2]
Metode 4
menggunakan reindex
atauloc
df.reindex(df.index.repeat(df.B.str.len())).assign(B=np.concatenate(df.B.values))
Out[554]:
A B
0 1 1
0 1 2
1 2 1
1 2 2
#df.loc[df.index.repeat(df.B.str.len())].assign(B=np.concatenate(df.B.values))
Metode 5
ketika daftar hanya berisi nilai unik:
df=pd.DataFrame({'A':[1,2],'B':[[1,2],[3,4]]})
from collections import ChainMap
d = dict(ChainMap(*map(dict.fromkeys, df['B'], df['A'])))
pd.DataFrame(list(d.items()),columns=df.columns[::-1])
Out[574]:
B A
0 1 1
1 2 1
2 3 2
3 4 2
Metode 6
menggunakan numpy
untuk kinerja tinggi:
newvalues=np.dstack((np.repeat(df.A.values,list(map(len,df.B.values))),np.concatenate(df.B.values)))
pd.DataFrame(data=newvalues[0],columns=df.columns)
A B
0 1 1
1 1 2
2 2 1
3 2 2
Metode 7
menggunakan fungsi dasar itertools
cycle
dan chain
: Solusi python murni hanya untuk bersenang-senang
from itertools import cycle,chain
l=df.values.tolist()
l1=[list(zip([x[0]], cycle(x[1])) if len([x[0]]) > len(x[1]) else list(zip(cycle([x[0]]), x[1]))) for x in l]
pd.DataFrame(list(chain.from_iterable(l1)),columns=df.columns)
A B
0 1 1
1 1 2
2 2 1
3 2 2
Menggeneralisasi ke banyak kolom
df=pd.DataFrame({'A':[1,2],'B':[[1,2],[3,4]],'C':[[1,2],[3,4]]})
df
Out[592]:
A B C
0 1 [1, 2] [1, 2]
1 2 [3, 4] [3, 4]
Fungsi self-def:
def unnesting(df, explode):
idx = df.index.repeat(df[explode[0]].str.len())
df1 = pd.concat([
pd.DataFrame({x: np.concatenate(df[x].values)}) for x in explode], axis=1)
df1.index = idx
return df1.join(df.drop(explode, 1), how='left')
unnesting(df,['B','C'])
Out[609]:
B C A
0 1 1 1
0 2 2 1
1 3 3 2
1 4 4 2
Unnesting berdasarkan kolom
Semua metode di atas berbicara tentang penarikan vertikal dan meledak, Jika Anda perlu mengeluarkan daftar horizontal , Periksa dengan pd.DataFrame
konstruktor
df.join(pd.DataFrame(df.B.tolist(),index=df.index).add_prefix('B_'))
Out[33]:
A B C B_0 B_1
0 1 [1, 2] [1, 2] 1 2
1 2 [3, 4] [3, 4] 3 4
Fungsi diperbarui
def unnesting(df, explode, axis):
if axis==1:
idx = df.index.repeat(df[explode[0]].str.len())
df1 = pd.concat([
pd.DataFrame({x: np.concatenate(df[x].values)}) for x in explode], axis=1)
df1.index = idx
return df1.join(df.drop(explode, 1), how='left')
else :
df1 = pd.concat([
pd.DataFrame(df[x].tolist(), index=df.index).add_prefix(x) for x in explode], axis=1)
return df1.join(df.drop(explode, 1), how='left')
Hasil Tes
unnesting(df, ['B','C'], axis=0)
Out[36]:
B0 B1 C0 C1 A
0 1 2 1 2 1
1 3 4 3 4 2