Membuat kerangka data dari kamus di mana entri memiliki panjang yang berbeda


114

Katakanlah saya memiliki kamus dengan 10 pasangan nilai kunci. Setiap entri memiliki larik numpy. Namun, panjang array tidak sama untuk semuanya.

Bagaimana cara membuat kerangka data di mana setiap kolom memiliki entri yang berbeda?

Ketika saya mencoba:

pd.DataFrame(my_dict)

Saya mendapat:

ValueError: arrays must all be the same length

Adakah cara untuk mengatasinya? Saya senang Panda digunakan NaNuntuk mengisi kolom-kolom itu untuk entri yang lebih pendek.

Jawaban:


132

Dengan Python 3.x:

In [6]: d = dict( A = np.array([1,2]), B = np.array([1,2,3,4]) )

In [7]: pd.DataFrame(dict([ (k,pd.Series(v)) for k,v in d.items() ]))
Out[7]: 
    A  B
0   1  1
1   2  2
2 NaN  3
3 NaN  4

Dengan Python 2.x:

ganti d.items()dengan d.iteritems().


Saya sedang mengerjakan masalah yang sama baru-baru ini, dan ini lebih baik daripada yang saya alami! Satu hal yang perlu diperhatikan, padding dengan NaN akan memaksa seri dtype menjadi float64, yang bisa menjadi masalah jika Anda perlu melakukan matematika integer.
mattexx

Anda selalu dapat mengajukan pertanyaan - banyak orang menjawabnya
Jeff

Anda perlu memberikan MVCE seperti yang disarankan oleh komentar
Jeff

3
@germ Anda mungkin ingin mengimpor Seri terlebih dahulu atau melakukan sesuatu seperti pd.Series(...) (dengan asumsi import pandas as pddi bagian impor)
Nima Mousavi

5
Versi yang lebih ringkas dari jawaban ini:pd.DataFrame({k: pd.Series(l) for k, l in d.items()})
user553965

82

Berikut cara sederhana untuk melakukannya:

In[20]: my_dict = dict( A = np.array([1,2]), B = np.array([1,2,3,4]) )
In[21]: df = pd.DataFrame.from_dict(my_dict, orient='index')
In[22]: df
Out[22]: 
   0  1   2   3
A  1  2 NaN NaN
B  1  2   3   4
In[23]: df.transpose()
Out[23]: 
    A  B
0   1  1
1   2  2
2 NaN  3
3 NaN  4

apakah ada pilihan lain untuk 'mengindeks'?
sAguinaga

@sAguinaga Ya:, columnstapi ini sudah default. Lihat dokumentasi pandas - pandas.DataFrame.from_dict
Murmel

15

Cara untuk merapikan sintaks Anda, tetapi pada dasarnya masih melakukan hal yang sama seperti jawaban lainnya, ada di bawah ini:

>>> mydict = {'one': [1,2,3], 2: [4,5,6,7], 3: 8}

>>> dict_df = pd.DataFrame({ key:pd.Series(value) for key, value in mydict.items() })

>>> dict_df

   one  2    3
0  1.0  4  8.0
1  2.0  5  NaN
2  3.0  6  NaN
3  NaN  7  NaN

Sintaks serupa juga ada untuk daftar:

>>> mylist = [ [1,2,3], [4,5], 6 ]

>>> list_df = pd.DataFrame([ pd.Series(value) for value in mylist ])

>>> list_df

     0    1    2
0  1.0  2.0  3.0
1  4.0  5.0  NaN
2  6.0  NaN  NaN

Sintaks lain untuk daftar adalah:

>>> mylist = [ [1,2,3], [4,5], 6 ]

>>> list_df = pd.DataFrame({ i:pd.Series(value) for i, value in enumerate(mylist) })

>>> list_df

   0    1    2
0  1  4.0  6.0
1  2  5.0  NaN
2  3  NaN  NaN

Anda juga mungkin harus mengubah hasil dan / atau mengubah tipe data kolom (float, integer, dll).


3

Padahal ini tidak langsung menjawab pertanyaan OP. Saya menemukan ini menjadi solusi yang sangat baik untuk kasus saya ketika saya memiliki array yang tidak sama dan saya ingin berbagi:

dari dokumentasi panda

In [31]: d = {'one' : Series([1., 2., 3.], index=['a', 'b', 'c']),
   ....:      'two' : Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}
   ....: 

In [32]: df = DataFrame(d)

In [33]: df
Out[33]: 
   one  two
a    1    1
b    2    2
c    3    3
d  NaN    4

3

Anda juga dapat menggunakan pd.concatbersama axis=1dengan daftar pd.Seriesobjek:

import pandas as pd, numpy as np

d = {'A': np.array([1,2]), 'B': np.array([1,2,3,4])}

res = pd.concat([pd.Series(v, name=k) for k, v in d.items()], axis=1)

print(res)

     A  B
0  1.0  1
1  2.0  2
2  NaN  3
3  NaN  4

2

Kedua baris berikut bekerja dengan sempurna:

pd.DataFrame.from_dict(df, orient='index').transpose() #A

pd.DataFrame(dict([ (k,pd.Series(v)) for k,v in df.items() ])) #B (Better)

Tetapi dengan% timeit di Jupyter, saya memiliki rasio kecepatan 4x untuk B vs A, yang cukup mengesankan terutama saat bekerja dengan kumpulan data yang besar (terutama dengan sejumlah besar kolom / fitur).


1

Jika Anda tidak ingin menampilkannya NaNdan Anda memiliki dua panjang tertentu, menambahkan 'spasi' di setiap sel yang tersisa juga akan berfungsi.

import pandas

long = [6, 4, 7, 3]
short = [5, 6]

for n in range(len(long) - len(short)):
    short.append(' ')

df = pd.DataFrame({'A':long, 'B':short}]
# Make sure Excel file exists in the working directory
datatoexcel = pd.ExcelWriter('example1.xlsx',engine = 'xlsxwriter')
df.to_excel(datatoexcel,sheet_name = 'Sheet1')
datatoexcel.save()

   A  B
0  6  5
1  4  6
2  7   
3  3   

Jika Anda memiliki lebih dari 2 panjang entri, disarankan untuk membuat fungsi yang menggunakan metode serupa.


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.