Sözlük listesini pandalara dönüştürme DataFrame


656

Bunun gibi sözlüklerin bir listesi var:

[{'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'}]

Ve bunu DataFrameböyle bir pandaya dönüştürmek istiyorum:

      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

Not: Sütunların sırası önemli değildir.

Sözlük listesini yukarıda gösterildiği gibi bir panda DataFrame'e nasıl dönüştürebilirim?

Yanıtlar:


950

Varsayalım ki d, dikte listeniz basitçe:

pd.DataFrame(d)

3
Anahtar / değer çiftlerinden birini indeks olarak nasıl kullanabilirsiniz (örn. Zaman)?
CatsLoveJazz

6
@CatsLoveJazz Daha df = df.set_index('time')sonra yapabilirsiniz
joris

1
@CatsLoveJazz Hayır, bir diksiyondan dönüştürürken bu mümkün değildir.
joris

6
Pandalar 0.19.2'den itibaren, belgelerde bundan bahsetmiyoruz, en azından için belgelerdepandas.DataFrame
Leo Alekseyev

1
Yuvalanmış bir sözlük '{"":{"...için json_normalize yaklaşımını kullandığınızı, @ cs95
Lorenz

136

Bir sözlük listesini panda DataFrame'e nasıl dönüştürebilirim?

Diğer cevaplar doğrudur, ancak bu yöntemlerin avantajları ve sınırlamaları açısından fazla bir şey açıklanmamıştır. Bu yazının amacı, farklı durumlarda bu yöntemlerin örneklerini göstermek, ne zaman kullanılacağını (ve ne zaman kullanılmayacağını) tartışmak ve alternatifler önermek olacaktır.


DataFrame(), DataFrame.from_records()Ve.from_dict()

Verilerinizin yapısına ve biçimine bağlı olarak, her üç yöntemin de çalıştığı veya bazılarının diğerlerinden daha iyi çalıştığı veya bazılarının hiç çalışmadığı durumlar vardır.

Çok tartışmalı bir örnek düşünün.

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}]

Bu liste mevcut her anahtarın bulunduğu "kayıtlardan" oluşur. Bu karşılaşabileceğiniz en basit durum.

# 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

Sözlük Yönelimleri Üzerine Kelime: orient='index'/'columns'

Devam etmeden önce, farklı sözlük yönlendirmesi türleri ve pandalarla destek arasında ayrım yapmak önemlidir. İki temel tür vardır: "sütunlar" ve "dizin".

orient='columns'
"Sütun" yönelimli sözlüklerin anahtarları, eşdeğer DataFrame'deki sütunlara karşılık gelir.

Örneğin, datayukarıdaki "sütunlar" yönündedir.

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

Not: Kullanıyorsanız pd.DataFrame.from_records, yönlendirmenin "sütun" olduğu varsayılır (başka türlü belirtemezsiniz) ve sözlükler buna göre yüklenir.

orient='index'
Bu yönlendirmeyle, anahtarların dizin değerlerine karşılık geldiği varsayılır. Bu tür veriler en uygunudur 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

Bu durum OP'de dikkate alınmaz, ancak yine de bilmek yararlıdır.

Özel Dizin Ayarlama

Sonuçta elde edilen DataFrame üzerinde özel bir dizine ihtiyacınız varsa, index=...bağımsız değişkeni kullanarak dizini ayarlayabilirsiniz .

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

Bu tarafından desteklenmiyor pd.DataFrame.from_dict.

Eksik Anahtarlar / Sütunlarla İşlem

Eksik anahtar / sütun değerlerine sahip sözlükler kullanılırken tüm yöntemler kullanıma hazırdır. Örneğin,

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

Sütunların Alt Kümesini Okuma

"Ya her bir sütunda okumak istemezsem?" columns=...Parametreyi kullanarak bunu kolayca belirleyebilirsiniz .

Örneğin, data2yukarıdaki örnek sözlüğe göre , yalnızca "A", "D" ve "F" sütunlarını okumak istiyorsanız, bunu bir listeyi ileterek yapabilirsiniz:

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

Bu, pd.DataFrame.from_dictvarsayılan yönlendirme "sütunları" ile desteklenmez .

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

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

Satır Alt Kümesini Okuma

Bu yöntemlerin hiçbiri doğrudan desteklenmez . Verilerinizi tekrarlamanız ve tekrarlarken yerinde ters silme yapmanız gerekecektir . Örneğin, sadece 0 ayıklamak için th ve 2 nd satırları data2yukarıdaki, şunları kullanabilirsiniz:

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

Her derde deva: json_normalizeİç İçe Veri için

Yukarıda özetlenen yöntemlere güçlü ve sağlam bir alternatif json_normalize, sözlük listeleri (kayıtları) ile çalışan ve ayrıca iç içe sözlükleri de işleyebilen işlevdir.

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

Yine, iletilen verilerin json_normalizesözlükler listesi (kayıtlar) biçiminde olması gerektiğini unutmayın.

Belirtildiği gibi, json_normalizeiç içe sözlükleri de işleyebilir. Dokümanlardan alınan bir örnek.

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

metaVe record_pathbağımsız değişkenleri hakkında daha fazla bilgi için belgelere bakın.


Özetleme

Aşağıda, desteklenen özelliklerin / işlevlerin yanı sıra yukarıda tartışılan tüm yöntemlerin bir tablosu bulunmaktadır.

resim açıklamasını buraya girin

* orient='columns'İle aynı efekti elde etmek için kullanın ve sonra transpoze edin orient='index'.


8
Vay! Tamam bu birleştirme SO yazı ile birlikte API aittir. Henüz yapmadıysanız panda belgelerine katkıda bulunmalısınız. Ted Petrou , Stack Overflow'daki pandaların popülerliği hakkında bir LinkedIn makalesi yayınladı ve iyi dokümantasyon eksikliğinin buradaki soruların hacmine katkıda bulunduğundan bahsediyor.
Scott Boston

2
@ScottBoston Kesinlikle haklısın, daha ciddi düşünmem gereken bir şey olduğunu biliyorum. Belgelerin, aynı kitlenin yalnızca bir kısmına ulaşacak soruları yayınlamaktan ziyade kullanıcılara yardımcı olmanın harika bir yolu olabileceğini düşünüyorum.
cs95

1
güzel bir cevap, bence en güncel pandalar sürümünde bu ortak soruyu tekrar
yürütebilme zamanı

3
@ely: Bu zaten cevap yazmamak için asla bir sebep değil . Herhangi bir cevap güncelliğini yitirebilir, oyladığımız şey budur ve burada farklı bakış açıları ve farklı hedefler mevcuttur ve aynı şeyi açıklamanın farklı yollarına sahip olmak her zaman değerlidir.
Martijn Pieters

1
@MartijnPieters Son iddianızı soruyorum ve katılmıyorum ama genel olarak size katılıyorum. Aynı soruya verilen farklı cevapları bir arada toplamak her zaman değer katkısı değildir, özellikle de bazı cevaplar diğer cevaplara dayalı güncellemeler veya koşullu farklılıklarsa. En kötü durumlarda, bu cevaplar bir araya getirildiğinde değer yıkıcı olabilir (daha eski cevabı daha doğru bir duruma düzenlemek için daha güncel cevabı kullanmak yerine). Ama yine de, sana büyük ölçüde katılıyorum.
ely

83

Pandalar 16.2'de pd.DataFrame.from_records(d)bunun işe yaramasını sağlamak zorunda kaldım.


1
Bu yaklaşım ile ilgili iyi bir şey de aynı şekilde çalışıyordeque
MBZ

3
0.17.1@joris çözümü ile pandalar ile iyi çalışıyor
Anton Protopopov

2
Usinig 0.14.1 ve @joris 'çözümü işe yaramadı ama bu işe yaradı
mchen

13
İçinde 0.18.1, from_recordssözlüklerin hepsinde aynı anahtarlar yoksa, bu kod kullanılmalıdır.
fredcallaway

23

Ayrıca şu şekilde de kullanabilirsiniz pd.DataFrame.from_dict(d):

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

Soru bir veri çerçevesi oluşturma hakkında listenin içinde dictbir tek gelen, s dictsize cevap varsayıldığı gibi.
a_guest

@a_guest güncellenmiş cevabı kontrol edin. Sanmıyorum.
shivsn

2

Birkaç kişinin bununla karşılaşacağını biliyorum ve burada hiçbir şey yardımcı olmaz. Bunu yapmanın en kolay yolu şöyle:

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)

Umarım bu birine yardımcı olur!


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'}]

ve basit çağrı:

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

print(pd)

0

Pyhton3: Daha önce listelenen çözümlerin çoğu işe yarıyor. Ancak, veri çerçevesinin satır_sayısının gerekli olmadığı ve her satırın (kayıt) ayrı ayrı yazılması gereken durumlar vardır.

Bu durumda aşağıdaki yöntem yararlıdır.

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])

0

Bir sözlük listesini panda DataFrame'e dönüştürmek için "append" kullanabilirsiniz:

Biz denilen bir sözlük dicve DIC 30 liste öğeleri vardır ( list1, list2, ..., list30)

  1. step1: sonucunuzu korumak için bir değişken tanımlayın (ör: total_df )
  2. 2. adım: başlat total_df ilelist1
  3. step3: tüm listeleri eklemek için "for loop" kullanın 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)])

Konularındaki ayrıntılı iki yaşında yanıtında @ cs95 tarafından özetlenen yaklaşımları üzerinden bu yaklaşıma yararı nedir DataFrame(), DataFrame.from_records()ve .from_dict()?
Jeremy Caney

Yukarıdaki tüm yöntemleri 30 listeden oluşan bir sözlük için test ettim, sadece Ekle fonksiyonunu kullanarak cevap aldım.
Armin Ahmadi Nasab
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.