ChatGPT解决这个技术问题 Extra ChatGPT

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

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


M
Mateen Ulhaq

如果 dsdict 的列表:

df = pd.DataFrame(ds)

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


如何使用其中一个键/值对作为索引(例如时间)?
@CatsLoveJazz 你可以在之后做 df = df.set_index('time')
@CatsLoveJazz 不,从字典转换时这是不可能的。
从 Pandas 0.19.2 开始,文档中没有提到这一点,至少在 pandas.DataFrame 的文档中没有
请注意,对于嵌套字典 '{"":{"...,您使用 json_normalize 方法,请参阅@cs95 的详细答案
c
cs95

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

读取行的子集

这些方法中的任何一个直接都不支持。您必须迭代数据并在迭代时就地执行 reverse delete。例如,要从上面的 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    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

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

总结

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

https://i.stack.imgur.com/SRbw9.png

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


哇!好的,这与 Merging SO post 一起属于 API。如果您还没有这样做,您应该为 pandas 文档做出贡献。 Ted Petrou 刚刚在 Stack Overflow 上发布了一篇关于 pandas 受欢迎程度的LinkedIn article,并提到缺乏良好的文档会导致此处出现大量问题。
@ScottBoston 你说得完全正确,我已经听了足够多的时间了,因为我知道这是我应该更加认真考虑的事情。我认为文档可以成为帮助用户的好方法,而不是发布只能触及一小部分相同受众的问题。
这尤其成问题,因为哪些方法适用于哪些情况的细节经常会发生变化,因此对 SO 进行冗长、深入的回答不仅不如 pandas 官方文档中有用,而且通常甚至有害或误导因为对函数内部的一些更改可能会突然使答案不正确或实际上是错误的,并且它没有明确链接到实际源代码库以标记文档更新。
这是一个很好的答案,我认为是时候让我们在最新的 pandas 版本下重新讨论那些常见问题了 :-)
@ely:无论如何,这绝不是不在这里写答案的理由。任何答案都可能过时,这就是我们投票支持的,这里存在不同的观点和不同的目标,用不同的方式来解释同一件事总是很有价值的。
A
Asclepius

在 pandas 16.2 中,我必须执行 pd.DataFrame.from_records(d) 才能使其正常工作。


这种方法的好处是它也适用于 deque
使用 @joris 解决方案的 pandas 0.17.1 可以正常工作
Usinig 0.14.1 和@joris 的解决方案不起作用,但这确实有效
0.18.1 中,如果字典并非都具有相同的键,则必须使用 from_records
s
shivsn

您还可以将 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

问题是关于从 dictlist 构造数据框,而不是像您在答案中假设的那样从单个 dict 构造数据框。
@a_guest 检查更新的答案。我不是假设。
C
Community

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

c
cs95

我发现最简单的方法是这样的:

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)

使用 pandas 时避免循环,循环 kill 是 pandas 的全部目的
我没有投反对票,但是虽然这在技术上可行,但它的性能却很差。有关详细信息,请参阅 this
v
vloubes

我有以下带有日期时间键和 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)

您正在更改 dataframe 的方向。选定的答案还会在列/垂直方向上为您提供 dataframe