Sebagai pengguna dengan Rdan python, saya telah melihat jenis pertanyaan ini beberapa kali.
Di R, mereka memiliki fungsi bawaan dari paket yang tidyrdipanggil unnest. Namun di Python( pandas) tidak ada fungsi bawaan untuk jenis pertanyaan ini.
Saya tahu objectkolom typeselalu membuat data sulit untuk diubah dengan pandasfungsi '. Ketika saya menerima data seperti ini, hal pertama yang terlintas di benak saya adalah 'meratakan' atau mengosongkan kolom.
Saya menggunakan pandasdan pythonfungsi untuk jenis pertanyaan ini. Jika Anda khawatir tentang kecepatan solusi di atas, periksa jawaban pengguna3483203, karena dia menggunakan numpydan sebagian besar waktu numpylebih cepat. Saya merekomendasikan Cpythondan numbajika 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 explodefungsi:
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 repeatdengan DataFramekonstruktor, 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: joinatau mergedengan indexsetelah '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 reindexdi 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 numpyuntuk 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 cycledan 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.DataFramekonstruktor
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