将字典列表转换为熊猫DataFrame

如何将字典列表转换为DataFrame?给定:

[{'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  year0       NaN      50        NaN  5:00  20101  february      25        NaN  6:00   NaN2   january      90        NaN  9:00   NaN3      june     NaN         20   NaN   NaN

注意:列的顺序无关紧要。

766416 次浏览

如果dsdict的列表:

df = pd.DataFrame(ds)

注意:这不适用于嵌套数据。

在熊猫16.2中,我必须做pd.DataFrame.from_records(d)才能使其发挥作用。

您也可以使用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    year0       NaN    50.0        NaN  5:00  2010.01  february    25.0        NaN  6:00     NaN2   january    90.0        NaN  9:00     NaN3      june     NaN       20.0   NaN     NaN

如何将字典列表转换为熊猫DataFrame?

其他答案是正确的,但没有太多解释这些方法的优点和局限性。这篇文章的目的是展示这些方法在不同情况下的例子,讨论何时使用(何时不使用),并提出替代方案。


#0#1#2

根据数据的结构和格式,在某些情况下,所有三种方法都有效,或者有些方法比其他方法更好,或者有些方法根本不起作用。

考虑一个非常做作的例子。

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  D0  5  0  3  31  7  9  3  52  2  4  7  6

字典方向: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  D0  5  0  3  31  7  9  3  52  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  D0  5  0  3  31  7  9  3  52  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  Da  5  0  3  3b  7  9  3  5c  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    F0  5.0  NaN  3.0  3.0  NaN  NaN1  7.0  9.0  NaN  NaN  NaN  5.02  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    F0  5.0  3.0  NaN1  7.0  NaN  5.02  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'

读取行的子集

这些方法都不支持直接。你必须迭代你的数据并在迭代时就地执行反向删除。例如,要从上面的data2中仅提取0th和2nd行,您可以使用:

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    E0  5.0  NaN  3  3.0  NaN1  NaN  4.0  7  NaN  6.0

万能药:嵌套数据#0

上述方法的一个强大而健壮的替代方法是json_normalize函数,它可以处理字典列表(记录),此外还可以处理嵌套字典。

pd.json_normalize(data)
A  B  C  D0  5  0  3  31  7  9  3  52  2  4  7  6
pd.json_normalize(data2)
A    B  C    D    E0  5.0  NaN  3  3.0  NaN1  NaN  4.0  7  NaN  6.0

同样,请记住,传递给json_normalize的数据需要采用字典列表(记录)格式。

如前所述,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.json_normalize(data_nested,record_path='counties',meta=['state', 'shortname', ['info', 'governor']])
name  population    state shortname info.governor0        Dade       12345  Florida        FL    Rick Scott1     Broward       40000  Florida        FL    Rick Scott2  Palm Beach       60000  Florida        FL    Rick Scott3      Summit        1234     Ohio        OH   John Kasich4    Cuyahoga        1337     Ohio        OH   John Kasich

有关metarecord_path参数的更多信息,请查看留档。


总结

这是上面讨论的所有方法的表格,以及支持的特性/功能。

在此处输入图片描述

*使用orient='columns'然后转置以获得与orient='index'相同的效果。

我找到的最简单的方法是这样的:

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)

Pyhton3:前面列出的大多数解决方案都有效。但是,在某些情况下,不需要row_number数据帧,并且必须单独写入每行(记录)。

在这种情况下,以下方法很有用。

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

我有以下带有datetime键和int值的dicts列表:

list = [{datetime.date(2022, 2, 10): 7}, {datetime.date(2022, 2, 11): 1}, {datetime.date(2022, 2, 11): 1}]

使用上面的方法将其转换为Dataframe时遇到了一个问题,因为它创建了带有日期列的Dataframe…

我的解决方案:

df = pd.DataFrame()for i in list:temp_df = pd.DataFrame.from_dict(i, orient='index')df = df.append(temp_df)