将字典列表转换为 pandas DataFrame
- 2024-11-26 08:36:00
- admin 原创
- 191
问题描述:
如何将字典列表转换为 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'}]
进入
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
解决方案 1:
如果ds
是 s 的列表dict
:
df = pd.DataFrame(ds)
注意:这不适用于嵌套数据。
解决方案 2:
如何将字典列表转换为 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'
在继续之前,重要的是要区分不同类型的字典方向以及 pandas 的支持。主要有两种类型:“列”和“索引”。
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.json_normalize(data)
A B C D
0 5 0 3 3
1 7 9 3 5
2 2 4 7 6
pd.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.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'
然后转置 可获得与 相同的效果orient='index'
。
解决方案 3:
在 pandas 16.2 中,我必须pd.DataFrame.from_records(d)
这样做才能使其正常工作。
解决方案 4:
您还可以使用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
解决方案 5:
Pyhton3:
前面列出的大多数解决方案都有效。但是,有些情况下不需要数据框的 row_number,并且必须单独写入每一行(记录)。在这种情况下,下面的方法很有用。
import csv
my file= 'C:UsersJohnDesktopexport_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])
解决方案 6:
如果字典中缺少键,简单的pd.DataFrame()
构造将通过为缺少的键分配 NaN 值来处理它。这会“弄乱”数据类型并将整数转换为浮点数。例如,使用 OP 中的示例数据,'year'
列中缺少值,这些值会转换为浮点数,这可能不是我们所希望的,因为我们现在有可空的整数数据类型。解决这个问题的一种方法是无论如何都要构造数据框,然后稍后使用来处理数据类型astype()
:
lst = [{'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'}]
dtypes = {'points': 'Int32', 'time': 'string', 'year': 'Int32', 'month': 'string', 'points_h1': 'Int32'}
df = pd.DataFrame(lst).astype(dtypes)
但是,如果键很多,则扩展性不佳。一种简单的开箱即用方法是将列表转换为 json 数组,然后使用 将其读取为 json pd.read_json
。它的好处是,您可以在构造期间设置 dtype,将整数转换为 Int dtype,但保留其他所有内容(例如字符串、浮点数等)不变。
import json, io # both of these are in the standard library
df = pd.read_json(io.StringIO(json.dumps(lst)), dtype='Int32')
解决方案 7:
我发现最简单的方法是这样的:
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)
解决方案 8:
我有以下带有datetime
键和 int 值的字典列表:
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)