关于python:将字典列表转换为pandas DataFrame

Convert list of dictionaries to a pandas DataFrame

我有一个这样的字典列表:

1
2
3
4
[{'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'}]

我想把它变成一只大熊猫,就像这样:

1
2
3
4
5
      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

注意:列的顺序并不重要。

如何将字典列表转换为如上所示的熊猫数据框?


假设d是你的口述清单,简单地说:

1
pd.DataFrame(d)


在《大熊猫》16.2版中,我必须做pd.DataFrame.from_records(d)才能让它发挥作用。


How do I convert a list of dictionaries to a pandas DataFrame?

The other answers are correct, but not much has been explained in terms of advantages and limitations of these methods. The aim of this post will be to show examples of these methods under different situations, discuss when to use (and when not to use), and suggest alternatives.

DataFrame(), DataFrame.from_records(), and .from_dict()

Depending on the structure and format of your data, there are situations where either all three methods work, or some work better than others, or some don't work at all.

Consider a very contrived example.

1
2
3
4
5
6
7
8
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}]

这个列表由"记录"组成,每个键都存在。这是您可能遇到的最简单的情况。

1
2
3
4
5
6
7
8
9
# 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'具有"列"方向的字典将其键对应于等效数据框中的列。

例如,上面的data位于"列"方向。

1
2
3
4
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}]
1
2
3
4
5
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

1
2
3
4
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}}
1
2
3
4
5
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中没有考虑,但仍有助于了解。

设置自定义索引

如果需要对生成的数据帧进行自定义索引,可以使用index=...参数进行设置。

1
2
3
4
5
6
7
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的支持。

处理缺少的键/列

处理缺少键/列值的字典时,所有方法都是现成的。例如,

1
2
3
4
data2 = [
     {'A': 5, 'C': 3, 'D': 3},
     {'A': 7, 'B': 9, 'F': 5},
     {'B': 4, 'C': 7, 'E': 6}]
1
2
3
4
5
6
7
8
9
# 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",可以通过传递一个列表来完成:

1
2
3
4
5
6
7
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不支持这种情况。

1
pd.DataFrame.from_dict(data2, orient='columns', columns=['A', 'B'])
1
ValueError: cannot use columns parameter with orient='columns'

正在读取行的子集

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

1
2
3
4
5
6
7
8
9
10
11
12
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函数是一种强有力的、健壮的替代方法,它与字典(记录)列表一起工作,此外还可以处理嵌套字典。

1
2
3
4
5
6
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
1
2
3
4
5
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还可以处理嵌套字典。以下是文档中的一个示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
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'}
]
1
2
3
4
5
6
7
8
9
10
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参数的更多信息,请查看文档。

总结能力

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

enter image description here


您也可以使用pd.DataFrame.from_dict(d)作为:

[cc lang="python"]In [8]: d = [{'points': 50, 'time': '5:00', 'year': 2010},
...: {'points': 25, 'time': '6:00', 'month':"february