แปลงรายการพจนานุกรมเป็น DataFrame แพนด้า


656

ฉันมีรายการพจนานุกรมเช่นนี้:

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

และฉันต้องการเปลี่ยนให้เป็นหมีแพนด้าDataFrameเช่นนี้:

      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

หมายเหตุ: ลำดับของคอลัมน์ไม่สำคัญ

ฉันจะเปลี่ยนรายการพจนานุกรมเป็น DataFrame แพนด้าตามที่แสดงด้านบนได้อย่างไร

คำตอบ:


950

หากว่าdเป็นรายการของ dicts ของคุณเพียง:

pd.DataFrame(d)

3
หนึ่งอาจใช้หนึ่งในคู่ของคีย์ / ค่าเป็นดัชนี (เช่นเวลา) ได้อย่างไร
CatsLoveJazz

6
@CatsLoveJazz คุณสามารถทำได้df = df.set_index('time')หลังจากนั้น
joris

1
@CatsLoveJazz ไม่นั่นเป็นไปไม่ได้เมื่อแปลงจาก dict
joris

6
ตั้งแต่ Pandas 0.19.2 ไม่มีการพูดถึงเรื่องนี้ในเอกสารประกอบอย่างน้อยไม่ได้อยู่ในเอกสารสำหรับpandas.DataFrame
Leo Alekseyev

1
โปรดทราบว่าสำหรับพจนานุกรมที่ซ้อนกัน'{"":{"...คุณใช้วิธี json_normalize ดูคำตอบโดยละเอียดของ @ cs95
Lorenz

136

ฉันจะแปลงรายการพจนานุกรมเป็น DataFrame แพนด้าได้อย่างไร

คำตอบอื่น ๆ นั้นถูกต้อง แต่ไม่ได้อธิบายมากนักในแง่ของข้อดีและข้อ จำกัด ของวิธีการเหล่านี้ จุดประสงค์ของโพสต์นี้คือเพื่อแสดงตัวอย่างของวิธีการเหล่านี้ภายใต้สถานการณ์ที่แตกต่างกันอภิปรายว่าจะใช้เมื่อไร (และเมื่อใดที่จะไม่ใช้) และแนะนำทางเลือกอื่น ๆ


DataFrame(), DataFrame.from_records()และ.from_dict()

ขึ้นอยู่กับโครงสร้างและรูปแบบของข้อมูลของคุณมีสถานการณ์ที่ทั้งสามวิธีการทำงานหรือบางอย่างทำงานได้ดีกว่าคนอื่นหรือบางคนไม่ทำงานเลย

ลองพิจารณาตัวอย่างที่วางแผนไว้มาก

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

รายการนี้ประกอบด้วย "บันทึก" ที่มีปุ่มทุกปุ่มอยู่ นี่เป็นกรณีที่ง่ายที่สุดที่คุณจะได้พบ

# 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

การวางแนวของ Word on Dictionary: orient='index'/'columns'

ก่อนดำเนินการต่อเป็นสิ่งสำคัญที่จะต้องแยกความแตกต่างระหว่างการวางแนวพจนานุกรมที่แตกต่างกันและการสนับสนุนกับแพนด้า มีสองประเภทหลัก: "คอลัมน์" และ "ดัชนี"

orient='columns'
พจนานุกรมที่มีการวางแนว "คอลัมน์" จะมีกุญแจของพวกเขาสอดคล้องกับคอลัมน์ใน DataFrame ที่เทียบเท่า

ตัวอย่างเช่นdataข้างต้นอยู่ใน "คอลัมน์" ตะวันออก

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

หมายเหตุ: หากคุณกำลังใช้pd.DataFrame.from_recordsการวางแนวจะถือว่าเป็น "คอลัมน์" (คุณไม่สามารถระบุเป็นอย่างอื่นได้) และพจนานุกรมจะถูกโหลดตามนั้น

orient='index'
ด้วยทิศทางนี้คีย์จะถือว่าสอดคล้องกับค่าดัชนี 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

กรณีนี้ไม่ได้พิจารณาใน OP แต่ก็ยังมีประโยชน์ที่จะรู้

การตั้งค่าดัชนีที่กำหนดเอง

หากคุณต้องการดัชนีที่กำหนดเองใน DataFrame ผลลัพธ์คุณสามารถตั้งค่าโดยใช้index=...อาร์กิวเมนต์

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

pd.DataFrame.from_dictนี้ไม่ได้รับการสนับสนุนโดย

การจัดการกับคีย์ / คอลัมน์ที่หายไป

วิธีการทั้งหมดทำงานนอกกรอบเมื่อจัดการพจนานุกรมด้วยค่าคีย์ / คอลัมน์ที่หายไป ตัวอย่างเช่น,

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

อ่านชุดย่อยของคอลัมน์

"จะเป็นอย่างไรถ้าฉันไม่ต้องการอ่านในทุกคอลัมน์" คุณสามารถระบุสิ่งนี้ได้อย่างง่ายดายโดยใช้columns=...พารามิเตอร์

ตัวอย่างเช่นจากพจนานุกรมตัวอย่างdata2ด้านบนหากคุณต้องการอ่านเฉพาะคอลัมน์ "A ',' D 'และ' F 'คุณสามารถทำได้โดยส่งรายการ:

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

สิ่งนี้ไม่ได้รับการสนับสนุนจากpd.DataFrame.from_dict"คอลัมน์" เริ่มต้น

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

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

อ่านชุดย่อยของแถว

ไม่ได้รับการสนับสนุนโดยวิธีการใด ๆ เหล่านี้โดยตรง คุณจะต้องวนซ้ำข้อมูลของคุณและทำการลบย้อนกลับในสถานที่ในขณะที่คุณทำซ้ำ ยกตัวอย่างเช่นในการสกัดเพียง 0 วันที่ 2 และครั้งที่แถวจากdata2ข้างต้นคุณสามารถใช้:

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

ยาครอบจักรวาล: json_normalizeสำหรับข้อมูลที่ซ้อนกัน

ทางเลือกที่แข็งแกร่งและมีประสิทธิภาพสำหรับวิธีการที่อธิบายไว้ข้างต้นคือjson_normalizeฟังก์ชันที่ทำงานกับรายการพจนานุกรม (บันทึก) และนอกจากนี้ยังสามารถจัดการพจนานุกรมที่ซ้อนกันได้อีกด้วย

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

อีกครั้งโปรดจำไว้ว่าข้อมูลที่ส่งผ่านไปยังjson_normalizeจำเป็นต้องอยู่ในรูปแบบ list-of-dictionaries (records)

ดังกล่าวjson_normalizeยังสามารถจัดการพจนานุกรมที่ซ้อนกัน นี่คือตัวอย่างที่นำมาจากเอกสาร

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

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับmetaและrecord_pathข้อโต้แย้งตรวจสอบเอกสารประกอบ


สรุป

นี่คือตารางของวิธีการทั้งหมดที่กล่าวถึงข้างต้นพร้อมกับคุณสมบัติ / ฟังก์ชันการทำงานที่รองรับ

ป้อนคำอธิบายรูปภาพที่นี่

* ใช้orient='columns'แล้ว transpose orient='index'ที่จะได้รับผลเช่นเดียวกับ


8
ว้าว! โอเคสิ่งนี้พร้อมกับการรวมโพสต์ SOไว้ใน API คุณควรมีส่วนร่วมในเอกสารของแพนด้าหากคุณยังไม่ได้ดำเนินการ Ted Petrou เพิ่งโพสต์บทความ LinkedInเกี่ยวกับความนิยมของหมีแพนด้าใน Stack Overflow และกล่าวถึงว่าการขาดเอกสารที่ดีทำให้เกิดคำถามมากมายที่นี่
Scott Boston

2
@ScottBoston ถูกต้องฉันได้ยินมาหลายครั้งแล้วว่าฉันรู้ว่ามันเป็นสิ่งที่ฉันควรให้ความสำคัญกับความคิด ฉันคิดว่าเอกสารเป็นวิธีที่ดีในการช่วยเหลือผู้ใช้มากกว่าการโพสต์คำถามที่เข้าถึงผู้ชมกลุ่มเดียวกัน
cs95

1
มันเป็นคำตอบที่ดีฉันคิดว่าถึงเวลาแล้วที่เราจะกลับมาเดินเล่นอีกครั้งในคำถามทั่วไปเหล่านั้นภายใต้เวอร์ชันแพนด้าล่าสุด :-)
YOBEN_S

3
@ely: ที่เคยมีเหตุผลที่จะไม่เขียนคำตอบที่นี่อยู่แล้ว คำตอบใด ๆอาจล้าสมัยนั่นคือสิ่งที่เราได้ลงคะแนนและมุมมองที่แตกต่างกันและเป้าหมายที่แตกต่างกันอยู่ที่นี่และมันมีค่าเสมอที่จะมีวิธีต่าง ๆ ในการอธิบายสิ่งเดียวกัน
Martijn Pieters

1
@MartijnPieters ฉันถามและไม่เห็นด้วยกับการยืนยันครั้งสุดท้ายของคุณ แต่โดยรวมแล้วฉันเห็นด้วยกับคุณ ไม่ใช่สิ่งที่มีค่าเพิ่มเติมเสมอไปในการเปรียบเทียบคำตอบที่แตกต่างกันสำหรับคำถามเดียวกันโดยเฉพาะอย่างยิ่งหากคำตอบบางคำตอบคือการปรับปรุงหรือความแตกต่างแบบมีเงื่อนไข ในกรณีที่เลวร้ายที่สุดคำตอบเหล่านั้นอาจเป็นอันตรายเมื่อเปรียบเทียบกัน (เทียบกับการใช้คำตอบที่อัปเดตมากขึ้นเพื่อแก้ไขคำตอบเก่าให้เป็นสถานะที่ถูกต้องมากขึ้น) แต่อีกครั้งฉันเห็นด้วยกับคุณเป็นส่วนใหญ่
ely

83

ในแพนด้า 16.2 ฉันต้องทำpd.DataFrame.from_records(d)เพื่อให้งานนี้สำเร็จ


1
สิ่งที่ดีเกี่ยวกับวิธีนี้ก็คือมันใช้ได้กับdeque
MBZ

3
ทำงานได้ดีกับหมีแพนด้า0.17.1ด้วย @joris solution
Anton Protopopov

2
Usinig 0.14.1 และ @joris 'แก้ปัญหาไม่ทำงาน แต่สิ่งนี้ได้
mchen

13
ใน0.18.1หนึ่งต้องใช้from_recordsหากพจนานุกรมไม่ได้ทั้งหมดมีคีย์เดียวกัน
fredcallaway

23

คุณยังสามารถใช้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

คำถามที่เป็นเรื่องเกี่ยวกับการสร้างกรอบข้อมูลจากรายการของdicts ไม่ได้มาจากที่เดียวdictที่คุณสันนิษฐานในคำตอบของคุณ
a_guest

@a_guest ตรวจสอบคำตอบที่อัพเดตแล้ว ฉันไม่ได้คิดเอาเอง
shivsn

2

ฉันรู้ว่าบางคนจะเจอกับสิ่งนี้และไม่พบสิ่งใดที่นี่ช่วยได้ วิธีที่ง่ายที่สุดที่ฉันพบว่าทำเช่นนี้:

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)

หวังว่านี่จะช่วยใครซักคน!


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

และโทรง่าย:

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

print(pd)

0

Pyhton3: โซลูชัน ส่วนใหญ่ที่แสดงรายการก่อนหน้านี้ทำงานได้ อย่างไรก็ตามมีอินสแตนซ์เมื่อไม่จำเป็นต้องมี row_number ของ dataframe และแต่ละแถว (บันทึก) ต้องถูกเขียนแยกกัน

วิธีการต่อไปนี้มีประโยชน์ในกรณีนั้น

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

สำหรับการแปลงรายการพจนานุกรมเป็น DataFrame แพนด้าคุณสามารถใช้ "ผนวก":

เรามีพจนานุกรมที่เรียกว่าdicและ DIC มี 30 รายการ ( list1, list2, ... list30)

  1. ขั้นที่ 1: กำหนดตัวแปรในการรักษาผลของคุณ (เช่นtotal_df)
  2. ขั้นที่ 2: เริ่มต้นtotal_dfด้วยlist1
  3. ขั้นที่ 3: ใช้ "for loop" เพื่อผนวกรายการทั้งหมดไปที่ 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)])

ผลประโยชน์ที่จะวิธีการนี้คืออะไรมากกว่าวิธีการที่ระบุไว้โดย @ cs95 ในรายละเอียดของคำตอบสองปีเก่าของพวกเขาเกี่ยวกับการDataFrame(), DataFrame.from_records()และ.from_dict()?
Jeremy Caney

ฉันทดสอบทุกวิธีข้างต้นสำหรับพจนานุกรมที่มี 30 รายการฉันได้รับคำตอบโดยใช้ฟังก์ชั่นผนวกเท่านั้น
Armin Ahmadi Nasab
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.