Ubah daftar kamus menjadi panda DataFrame

657

Saya punya daftar kamus seperti ini:

[{'points': 50, 'time': '5:00', 'year': 2010}, 
{'points': 25, 'time': '6:00', 'month': "february"}, 
{'points':90, 'time': '9:00', 'month': 'january'}, 
{'points_h1':20, 'month': 'june'}]

Dan saya ingin mengubah ini menjadi panda DataFrameseperti ini:

      month  points  points_h1  time  year
0       NaN      50        NaN  5:00  2010
1  february      25        NaN  6:00   NaN
2   january      90        NaN  9:00   NaN
3      june     NaN         20   NaN   NaN

Catatan: Urutan kolom tidak masalah.

Bagaimana saya bisa mengubah daftar kamus menjadi panda DataFrame seperti yang ditunjukkan di atas?

appleLover
sumber

Jawaban:

951

Misalkan dadalah daftar dikt Anda, cukup:

pd.DataFrame(d)
Joris
sumber
3
Bagaimana mungkin seseorang menggunakan salah satu pasangan kunci / nilai sebagai indeks (mis. Waktu)?
CatsLoveJazz
6
@CatsLoveJazz Anda hanya dapat melakukan df = df.set_index('time')sesudahnya
joris
1
@CatsLoveJazz Tidak, itu tidak mungkin ketika mengkonversi dari dikt.
joris
6
Pada Pandas 0.19.2, tidak ada yang menyebutkan hal ini dalam dokumentasi, setidaknya tidak dalam dokumen untukpandas.DataFrame
Leo Alekseyev
1
'{"":{"...Harap diingat bahwa untuk kamus bersarang Anda menggunakan pendekatan json_normalize, lihat jawaban terperinci dari @ cs95
Lorenz
136

Bagaimana cara mengonversi daftar kamus ke panda DataFrame?

Jawaban lainnya benar, tetapi tidak banyak yang dijelaskan dalam hal kelebihan dan keterbatasan metode ini. Tujuan dari posting ini adalah untuk menunjukkan contoh-contoh metode ini dalam situasi yang berbeda, mendiskusikan kapan harus menggunakan (dan kapan tidak menggunakan), dan menyarankan alternatif.


DataFrame(),, DataFrame.from_records()dan.from_dict()

Bergantung pada struktur dan format data Anda, ada situasi di mana ketiga metode bekerja, atau beberapa bekerja lebih baik daripada yang lain, atau beberapa tidak berfungsi sama sekali.

Pertimbangkan contoh yang sangat dibuat-buat.

np.random.seed(0)
data = pd.DataFrame(
    np.random.choice(10, (3, 4)), columns=list('ABCD')).to_dict('r')

print(data)
[{'A': 5, 'B': 0, 'C': 3, 'D': 3},
 {'A': 7, 'B': 9, 'C': 3, 'D': 5},
 {'A': 2, 'B': 4, 'C': 7, 'D': 6}]

Daftar ini terdiri dari "catatan" dengan setiap kunci hadir. Ini adalah kasus paling sederhana yang bisa Anda temui.

# The following methods all produce the same output.
pd.DataFrame(data)
pd.DataFrame.from_dict(data)
pd.DataFrame.from_records(data)

   A  B  C  D
0  5  0  3  3
1  7  9  3  5
2  2  4  7  6

Kata pada Orientasi Kamus: orient='index'/'columns'

Sebelum melanjutkan, penting untuk membuat perbedaan antara berbagai jenis orientasi kamus, dan dukungan dengan panda. Ada dua tipe utama: "kolom", dan "indeks".

orient='columns'
Kamus dengan orientasi "kolom" akan memiliki kunci sesuai dengan kolom dalam DataFrame yang setara.

Sebagai contoh, di dataatas adalah dalam orientasi "kolom".

data_c = [
 {'A': 5, 'B': 0, 'C': 3, 'D': 3},
 {'A': 7, 'B': 9, 'C': 3, 'D': 5},
 {'A': 2, 'B': 4, 'C': 7, 'D': 6}]

pd.DataFrame.from_dict(data_c, orient='columns')

   A  B  C  D
0  5  0  3  3
1  7  9  3  5
2  2  4  7  6

Catatan: Jika Anda menggunakan pd.DataFrame.from_records, orientasi diasumsikan "kolom" (Anda tidak dapat menentukan sebaliknya), dan kamus akan dimuat sesuai.

orient='index'
Dengan orientasi ini, kunci diasumsikan sesuai dengan nilai indeks. Jenis data ini paling cocok untuk pd.DataFrame.from_dict.

data_i ={
 0: {'A': 5, 'B': 0, 'C': 3, 'D': 3},
 1: {'A': 7, 'B': 9, 'C': 3, 'D': 5},
 2: {'A': 2, 'B': 4, 'C': 7, 'D': 6}}

pd.DataFrame.from_dict(data_i, orient='index')

   A  B  C  D
0  5  0  3  3
1  7  9  3  5
2  2  4  7  6

Kasus ini tidak dipertimbangkan dalam OP, tetapi masih berguna untuk diketahui.

Pengaturan Indeks Kustom

Jika Anda memerlukan indeks khusus pada DataFrame yang dihasilkan, Anda dapat mengaturnya menggunakan index=...argumen.

pd.DataFrame(data, index=['a', 'b', 'c'])
# pd.DataFrame.from_records(data, index=['a', 'b', 'c'])

   A  B  C  D
a  5  0  3  3
b  7  9  3  5
c  2  4  7  6

Ini tidak didukung oleh pd.DataFrame.from_dict.

Berurusan dengan Tombol / Kolom yang Hilang

Semua metode bekerja di luar kotak saat menangani kamus dengan nilai kunci / kolom yang hilang. Sebagai contoh,

data2 = [
     {'A': 5, 'C': 3, 'D': 3},
     {'A': 7, 'B': 9, 'F': 5},
     {'B': 4, 'C': 7, 'E': 6}]

# The methods below all produce the same output.
pd.DataFrame(data2)
pd.DataFrame.from_dict(data2)
pd.DataFrame.from_records(data2)

     A    B    C    D    E    F
0  5.0  NaN  3.0  3.0  NaN  NaN
1  7.0  9.0  NaN  NaN  NaN  5.0
2  NaN  4.0  7.0  NaN  6.0  NaN

Membaca Subset Kolom

"Bagaimana jika saya tidak ingin membaca di setiap kolom"? Anda dapat dengan mudah menentukan ini menggunakan columns=...parameter.

Misalnya, dari kamus contoh di data2atas, jika Anda hanya ingin membaca kolom "A ',' D ', dan' F ', Anda dapat melakukannya dengan melewati daftar:

pd.DataFrame(data2, columns=['A', 'D', 'F'])
# pd.DataFrame.from_records(data2, columns=['A', 'D', 'F'])

     A    D    F
0  5.0  3.0  NaN
1  7.0  NaN  5.0
2  NaN  NaN  NaN

Ini tidak didukung oleh pd.DataFrame.from_dictdengan "kolom" orientasi default.

pd.DataFrame.from_dict(data2, orient='columns', columns=['A', 'B'])

ValueError: cannot use columns parameter with orient='columns'

Membaca Subset Baris

Tidak didukung oleh metode ini secara langsung . Anda harus beralih pada data Anda dan melakukan penghapusan terbalik di tempat saat Anda mengulanginya. Misalnya, untuk mengekstrak hanya 0 th dan 2 nd baris dari data2atas, Anda dapat menggunakan:

rows_to_select = {0, 2}
for i in reversed(range(len(data2))):
    if i not in rows_to_select:
        del data2[i]

pd.DataFrame(data2)
# pd.DataFrame.from_dict(data2)
# pd.DataFrame.from_records(data2)

     A    B  C    D    E
0  5.0  NaN  3  3.0  NaN
1  NaN  4.0  7  NaN  6.0

The Panacea: json_normalize for Nested Data

Alternatif yang kuat dan kuat untuk metode yang diuraikan di atas adalah json_normalizefungsi yang bekerja dengan daftar kamus (catatan), dan selain itu juga dapat menangani kamus bersarang.

pd.io.json.json_normalize(data)

   A  B  C  D
0  5  0  3  3
1  7  9  3  5
2  2  4  7  6

pd.io.json.json_normalize(data2)

     A    B  C    D    E
0  5.0  NaN  3  3.0  NaN
1  NaN  4.0  7  NaN  6.0

Sekali lagi, perlu diingat bahwa data yang diteruskan json_normalizeharus dalam format daftar (kamus).

Seperti disebutkan, json_normalizejuga dapat menangani kamus bersarang. Berikut ini contoh yang diambil dari dokumentasi.

data_nested = [
  {'counties': [{'name': 'Dade', 'population': 12345},
                {'name': 'Broward', 'population': 40000},
                {'name': 'Palm Beach', 'population': 60000}],
   'info': {'governor': 'Rick Scott'},
   'shortname': 'FL',
   'state': 'Florida'},
  {'counties': [{'name': 'Summit', 'population': 1234},
                {'name': 'Cuyahoga', 'population': 1337}],
   'info': {'governor': 'John Kasich'},
   'shortname': 'OH',
   'state': 'Ohio'}
]

pd.io.json.json_normalize(data_nested, 
                          record_path='counties', 
                          meta=['state', 'shortname', ['info', 'governor']])

         name  population    state shortname info.governor
0        Dade       12345  Florida        FL    Rick Scott
1     Broward       40000  Florida        FL    Rick Scott
2  Palm Beach       60000  Florida        FL    Rick Scott
3      Summit        1234     Ohio        OH   John Kasich
4    Cuyahoga        1337     Ohio        OH   John Kasich

Untuk informasi lebih lanjut tentang argumen metadan record_path, periksa dokumentasi.


Meringkas

Berikut adalah tabel dari semua metode yang dibahas di atas, bersama dengan fitur / fungsi yang didukung.

masukkan deskripsi gambar di sini

* Gunakan orient='columns'dan kemudian transpos untuk mendapatkan efek yang sama dengan orient='index'.

cs95
sumber
8
Wow! Oke ini bersama dengan menggabungkan pos SO milik di API. Anda harus berkontribusi pada dokumentasi panda jika Anda belum melakukannya. Ted Petrou baru saja memposting artikel LinkedIn tentang popularitas panda di Stack Overflow dan menyebutkan bahwa kurangnya dokumentasi yang baik berkontribusi pada volume pertanyaan di sini.
Scott Boston
2
@ScottBoston Anda benar sekali, saya sudah mendengarnya cukup banyak sekarang karena saya tahu itu adalah sesuatu yang harus saya pikirkan lebih serius. Saya pikir dokumentasi bisa menjadi cara yang bagus untuk membantu pengguna, lebih dari memposting pertanyaan yang hanya akan menjangkau sebagian kecil dari audiens yang sama.
cs95
1
itu adalah jawaban yang bagus, saya pikir ini saatnya bagi kita untuk kembali membahas pertanyaan umum di bawah versi panda terbaru :-)
YOBEN_S
3
@ely: toh itu bukan alasan untuk tidak menulis jawaban di sini . Setiap jawaban dapat menjadi usang, bahwa ini apa yang telah kita voting untuk, dan perspektif yang berbeda dan tujuan yang berbeda ada di sini, dan itu selalu berharga untuk memiliki cara yang berbeda untuk menjelaskan hal yang sama.
Martijn Pieters
1
@ MartijnPieters Saya mempertanyakan dan tidak setuju dengan pernyataan terakhir Anda tetapi secara keseluruhan saya setuju dengan Anda. Tidak selalu nilai tambah untuk menyusun jawaban yang berbeda untuk pertanyaan yang sama secara bersama-sama, terutama jika beberapa jawaban adalah pembaruan atau perbedaan bersyarat berdasarkan jawaban lain. Dalam kasus-kasus terburuk, jawaban-jawaban itu dapat merusak nilai ketika disusun bersama (sebagai lawan dari menggunakan jawaban yang lebih diperbarui untuk hanya mengedit jawaban yang lebih tua menjadi keadaan yang lebih benar). Tetapi sekali lagi, saya sangat setuju dengan Anda.
ely
83

Dalam panda 16.2, saya harus melakukan pd.DataFrame.from_records(d)ini agar berhasil.

szeitlin
sumber
1
hal yang baik tentang pendekatan ini adalah ia juga bekerja dengandeque
MBZ
3
berfungsi dengan baik dengan panda 0.17.1dengan solusi @ joris
Anton Protopopov
2
Solusi Usinig 0.14.1 dan @joris tidak bekerja tetapi ini berhasil
mchen
13
Dalam 0.18.1, seseorang harus menggunakan from_recordskamus jika tidak semua memiliki kunci yang sama.
fredcallaway
23

Anda juga dapat menggunakan pd.DataFrame.from_dict(d)sebagai:

In [8]: d = [{'points': 50, 'time': '5:00', 'year': 2010}, 
   ...: {'points': 25, 'time': '6:00', 'month': "february"}, 
   ...: {'points':90, 'time': '9:00', 'month': 'january'}, 
   ...: {'points_h1':20, 'month': 'june'}]

In [12]: pd.DataFrame.from_dict(d)
Out[12]: 
      month  points  points_h1  time    year
0       NaN    50.0        NaN  5:00  2010.0
1  february    25.0        NaN  6:00     NaN
2   january    90.0        NaN  9:00     NaN
3      june     NaN       20.0   NaN     NaN
shivsn
sumber
Pertanyaannya adalah tentang membangun sebuah frame data dari daftar dari dicts, bukan dari satu dictseperti yang Anda diasumsikan dalam jawaban Anda.
a_guest
@ a_guest periksa jawaban yang diperbarui. Saya tidak berasumsi.
shivsn
2

Saya tahu beberapa orang akan menemukan ini dan tidak menemukan apa pun di sini yang membantu. Cara termudah yang saya temukan untuk melakukannya adalah seperti ini:

dict_count = len(dict_list)
df = pd.DataFrame(dict_list[0], index=[0])
for i in range(1,dict_count-1):
    df = df.append(dict_list[i], ignore_index=True)

Semoga ini bisa membantu seseorang!

scottapotamus
sumber
1
list=[{'points': 50, 'time': '5:00', 'year': 2010}, 
{'points': 25, 'time': '6:00', 'month': "february"}, 
{'points':90, 'time': '9:00', 'month': 'january'}, 
{'points_h1':20, 'month': 'june'}]

dan panggilan sederhana:

pd=DataFrame.from_dict(list, orient='columns', dtype=None)

print(pd)
Günel
sumber
0

Pyhton3: Sebagian besar solusi yang terdaftar sebelumnya berfungsi. Namun, ada beberapa contoh ketika row_number dari dataframe tidak diperlukan dan setiap baris (catatan) harus ditulis secara individual.

Metode berikut berguna dalam kasus itu.

import csv

my file= 'C:\Users\John\Desktop\export_dataframe.csv'

records_to_save = data2 #used as in the thread. 


colnames = list[records_to_save[0].keys()] 
# remember colnames is a list of all keys. All values are written corresponding
# to the keys and "None" is specified in case of missing value 

with open(myfile, 'w', newline="",encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerow(colnames)
    for d in records_to_save:
        writer.writerow([d.get(r, "None") for r in colnames])
Soum
sumber
0

Untuk mengonversi daftar kamus ke panda DataFrame, Anda dapat menggunakan "append":

Kami memiliki kamus yang disebut dicdan dic memiliki 30 daftar item ( list1, list2, ..., list30)

  1. langkah1: tentukan variabel untuk menjaga hasil Anda (mis: total_df )
  2. step2: menginisialisasi total_df denganlist1
  3. step3: gunakan "for loop" untuk menambahkan semua daftar total_df
total_df=list1
nums=Series(np.arange(start=2, stop=31))
for num in nums:
    total_df=total_df.append(dic['list'+str(num)])
Armin Ahmadi Nasab
sumber
Apa manfaat pendekatan ini selama pendekatan digariskan oleh @ cs95 dalam jawaban berusia dua tahun rinci mengenai DataFrame(), DataFrame.from_records()dan .from_dict()?
Jeremy Caney
Saya menguji semua metode di atas untuk kamus yang memiliki 30 daftar, saya hanya mendapatkan jawaban menggunakan fungsi Tambah.
Armin Ahmadi Nasab