将字典列表转换为Pandas 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

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

如何将字典列表转换为如上所述的pandas DataFrame?

Answers:


949

假设d您的字典列表很简单:

pd.DataFrame(d)

3
一个人如何使用键/值对之一作为索引(例如时间)?
CatsLoveJazz

6
@CatsLoveJazz你可以做df = df.set_index('time')之后
里斯

1
@CatsLoveJazz不,从字典转换时不可能。
joris

6
从Pandas 0.19.2开始,文档中没有提及这一点,至少在文档中没有提及pandas.DataFrame
Leo Alekseyev

1
请注意,对于嵌套字典,'{"":{"...您可以使用json_normalize方法,请参阅@ cs95的详细答案
Lorenz

136

如何将字典列表转换为Pandas 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

词典定位词: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必须采用字典列表(记录)格式。

如前所述,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

有关metarecord_path参数的更多信息,请查阅文档。


总结

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

在此处输入图片说明

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


8
哇!好的,这与合并SO帖子一起属于API。如果您尚未这样做,则应该为熊猫文档做出贡献。泰德·彼得鲁(Ted Petrou)刚刚在LinkedIn上发表了一篇有关Stack Overflow上熊猫的流行的文章,并提到缺乏好的文档会导致这里的问题很多。
斯科特·波士顿

2
@ScottBoston你说的很对,现在我已经听到足够多的时间了,我知道这是我应该认真考虑的事情。我认为文档可以是帮助用户的好方法,而不仅仅是发布仅覆盖少数受众的问题。
cs95

1
这是一个很好的答案,我认为现在是时候让我们重新讨论一下最新的熊猫版本下的常见问题:-)
YOBEN_S 18/12/18

3
@ely:无论如何,这绝不是在这里不写答案的理由。任何答案都可能过时,这就是我们的投票结果,这里存在不同的观点和不同的目标,采用不同的方式来解释同一件事总是很有价值的。
马丁·彼得斯

1
@MartijnPieters我质疑并不同意你的最后主张,但总的来说,我同意你的看法。将同一问题的不同答案整理到一起并不总是有价值的,特别是如果某些答案是基于其他答案的更新或条件差异时。在最坏的情况下,这些答案整理在一起时可能会破坏价值(与使用更新的答案来简单地将较旧的答案编辑为更正确的状态相反)。但是,我再次同意你的看法。
ely

83

在熊猫16.2中,我必须做一些pd.DataFrame.from_records(d)才能使它起作用。


1
这种方法的好处是它也可以与deque
MBZ

3
0.17.1@joris解决方案可与熊猫配合使用
Anton Protopopov

2
Usinig 0.14.1和@joris的解决方案无法正常工作,但这确实有效
mchen

13
在中0.18.1from_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,并且必须单独写入每一行(记录)。

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

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

要将字典列表转换为pandas DataFrame,可以使用“ append”:

我们有一个叫做字典dic和DIC有30个列表项(list1list2,... list30

  1. 步骤1:定义一个变量保持你的结果(例如:total_df
  2. 第二步:初始化total_dflist1
  3. 第三步:使用“ for循环”将所有列表附加到 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()
杰里米·卡尼

我对具有30个列表的字典测试了上述所有方法,但仅使用Append函数得到了答案。
Armin Ahmadi Nasab
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.