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.

Josh
sumber

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().

Jeff
sumber
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
dezan
sumber
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).

OrangeSherbet
sumber
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
pengguna2015487
sumber
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
jpp
sumber
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).

Ismail Hachimi
sumber
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.

Rohan Chandratre
sumber
-3

pd.DataFrame ([my_dict]) bisa!

john sukacita
sumber
tidak jika array dalam dict memiliki panjang yang berbeda
baxx