从字典列表创建一个 pandas DataFrame,字典键设置为行标签
Create a pandas DataFrame from a list of dictionaries with dictionary keys set as row labels
我有一个字典列表。每个字典都包含一个键值对。我想将这个列表转换成一个 pandas DataFrame,它有一个“时间”列,其中包含每个字典中行中的值,每行的标签是相应字典项中的键。
例如,我将只显示列表中的前两个元素:
list_example = [{'companies_info_5000_5100': 121.20147228240967},\
{'companies_info_5100_5200': 116.49221062660217}]
从这个 list_example
我想创建一个像这样的 DataFrame:
time
companies_info_5000_5100
121.201472
companies_info_5100_5200
116.492211
我搜索了可能的解决方案并提出了我自己的解决方案,如下所示:
import pandas as pd
df_list = []
for d in list_example:
d_df = pd.DataFrame.from_dict(d, orient="index", columns=["time"])
df_list.append(d_df)
df = pd.concat(df_list,axis= 0)
有了这段代码,我得到了我想要的,但是我确信一定有一些函数可以在没有 for 循环的情况下更有效地执行此操作。例如,如果我 运行 df = pd.DataFrame(df_list)
,那么它会创建一个 DataFrame,但字典键用作列,我在 DataFrame 中得到 NaN。我确信必须对该函数进行一些修改,告诉 pandas 使用键作为行标签。我正在寻找这个更简单、更优雅和 Pythonic 的解决方案。
就我在这里搜索而言,我找不到答案。
试试这个
# build a nested dict from list_example and build df
df = pd.DataFrame.from_dict({k: {'time': v} for d in list_example for k,v in d.items()}, orient='index')
print(df)
time
companies_info_5000_5100 121.201472
companies_info_5100_5200 116.492211
您可以使用:
df = (pd.concat(map(pd.Series, list_example))
.to_frame('time')
)
输出:
time
companies_info_5000_5100 121.201472
companies_info_5100_5200 116.492211
可能的解决方案之一是:
- 从每个字典创建一个系列,
- 连接它们(到目前为止结果仍然是 Series),
- 将其转换为 DataFrame,设置(唯一)列的名称。
执行此操作的代码是:
result = pd.concat([ pd.Series(d.values(), index=d.keys())
for d in list_example ]).to_frame('time')
对于你的示例数据,我得到了:
time
companies_info_5000_5100 121.201472
companies_info_5100_5200 116.492211
Pandas接近
pd.DataFrame(list_example).stack().droplevel(0).to_frame('time')
time
companies_info_5000_5100 121.201472
companies_info_5100_5200 116.492211
这个问题收到了 4 个有用的答案。
他们都工作并完成工作虽然根据Whosebug 规则,只允许一个接受的答案。所以,我决定检查他们的速度并接受最有效(最快)的答案。
为此,我人工创建了一个长度为 100,000 的字典列表:
check_length = 100000
list_example = []
for i in range(check_length):
list_example.append({f"companies_info_{i}": i})
然后,我定义了4个方法
Method name
Author
Method 1
Me
Method 2
My own suggested solution described in the question
Method 3
@mozway
Method 4
@not a robot
Method 5
@Valdi_Bo
我放弃了@Shubham Sharma 建议的最后一种称为 Pandas 方法 的方法,因为即使是 12 GB 的 RAM 也不够用。所以,显然这是最糟糕的方式。
包含100000个词典的列表迭代100次的结果如下:
Method name
Author
Results
Method 1
Me
58.829195756912235, 95% CI (58.436393856257794, 59.221997657566675)
Method 2
My own suggested solution described in the question
28.41278486251831, 95% CI (28.330043057325845, 28.495526667710777)
Method 3
@mozway
17.587587616443635, 95% CI (17.526133899890418, 17.649041332996852)
Method 4
@not a robot
0.20350171089172364, 95% CI (0.19587073491102097, 0.2111326868724263)
Method 5
@Valdi_Bo
15.767115621566772, 95% CI (15.721122343444568, 15.813108899688975)
P.S。如果有人对我检查每种情况的速度的代码感兴趣,请看这里:
import pandas as pd
import numpy as np
import time
import math
# Method 1
def get_frame_method_1(l):
list_example_d = {"time": l}
df_1 = pd.DataFrame.from_dict(data=list_example_d, orient="columns")
index_list = []
for count, d in enumerate(df_1.time):
index_list.extend(list(d.keys()))
df_1.time[count]= list(d.values())[0]
df_1.index= index_list
return df_1
# Method 2
def get_frame_method_2(l):
df_list = []
for d in l:
d_df = pd.DataFrame.from_dict(data=d, orient="index", columns=["time"])
df_list.append(d_df)
df_2 = pd.concat(df_list, axis= 0)
return df_2
# Method 3
def get_frame_method_3(l):
df_3 = (pd.concat(map(pd.Series, l))
.to_frame('time')
)
return df_3
# Method 4
def get_frame_method_4(l):
# build a nested dict from list_example and build df
df_4 = pd.DataFrame.from_dict({k: {'time': v} for d in l for k,v in d.items()}, orient='index')
return df_4
# Method 5
def get_frame_method_5(l):
df_5 = pd.concat([ pd.Series(d.values(), index=d.keys())
for d in l ]).to_frame('time')
return df_4
check_length = 100000
list_example = []
for i in range(check_length):
list_example.append({f"companies_info_{i}": i})
total_time_1_d = {}
for i in range(100):
t_0 = time.time()
df_1 = get_frame_method_1(list_example)
t_1 = time.time()
df_2 = get_frame_method_2(list_example)
t_2 = time.time()
df_3 = get_frame_method_3(list_example)
t_3 = time.time()
df_4 = get_frame_method_4(list_example)
t_4 = time.time()
df_5= get_frame_method_5(list_example)
t_5 = time.time()
total_time_1_d[f"{i}"] = {"Method 1": (t_1-t_0), "Method 2": (t_2-t_1), "Method 3": (t_3-t_2), "Method 4": (t_4-t_3), "Method 5": (t_5-t_4)}
print(i)
total_time_df = pd.DataFrame.from_dict(data= total_time_1_d, orient="index")
for i in range(5):
print(f"Method {i+1}: Mean - {total_time_df.describe().iloc[1, i]}, 95% CI ({total_time_df.describe().iloc[1, i]-1.96*(total_time_df.describe().iloc[2, i])/math.sqrt((total_time_df.describe().iloc[0, i]))}, {total_time_df.describe().iloc[1, i]+1.96*(total_time_df.describe().iloc[2, i])/math.sqrt((total_time_df.describe().iloc[0, i]))})")
我有一个字典列表。每个字典都包含一个键值对。我想将这个列表转换成一个 pandas DataFrame,它有一个“时间”列,其中包含每个字典中行中的值,每行的标签是相应字典项中的键。
例如,我将只显示列表中的前两个元素:
list_example = [{'companies_info_5000_5100': 121.20147228240967},\
{'companies_info_5100_5200': 116.49221062660217}]
从这个 list_example
我想创建一个像这样的 DataFrame:
time | |
---|---|
companies_info_5000_5100 | 121.201472 |
companies_info_5100_5200 | 116.492211 |
我搜索了可能的解决方案并提出了我自己的解决方案,如下所示:
import pandas as pd
df_list = []
for d in list_example:
d_df = pd.DataFrame.from_dict(d, orient="index", columns=["time"])
df_list.append(d_df)
df = pd.concat(df_list,axis= 0)
有了这段代码,我得到了我想要的,但是我确信一定有一些函数可以在没有 for 循环的情况下更有效地执行此操作。例如,如果我 运行 df = pd.DataFrame(df_list)
,那么它会创建一个 DataFrame,但字典键用作列,我在 DataFrame 中得到 NaN。我确信必须对该函数进行一些修改,告诉 pandas 使用键作为行标签。我正在寻找这个更简单、更优雅和 Pythonic 的解决方案。
就我在这里搜索而言,我找不到答案。
试试这个
# build a nested dict from list_example and build df
df = pd.DataFrame.from_dict({k: {'time': v} for d in list_example for k,v in d.items()}, orient='index')
print(df)
time
companies_info_5000_5100 121.201472
companies_info_5100_5200 116.492211
您可以使用:
df = (pd.concat(map(pd.Series, list_example))
.to_frame('time')
)
输出:
time
companies_info_5000_5100 121.201472
companies_info_5100_5200 116.492211
可能的解决方案之一是:
- 从每个字典创建一个系列,
- 连接它们(到目前为止结果仍然是 Series),
- 将其转换为 DataFrame,设置(唯一)列的名称。
执行此操作的代码是:
result = pd.concat([ pd.Series(d.values(), index=d.keys())
for d in list_example ]).to_frame('time')
对于你的示例数据,我得到了:
time
companies_info_5000_5100 121.201472
companies_info_5100_5200 116.492211
Pandas接近
pd.DataFrame(list_example).stack().droplevel(0).to_frame('time')
time
companies_info_5000_5100 121.201472
companies_info_5100_5200 116.492211
这个问题收到了 4 个有用的答案。
他们都工作并完成工作虽然根据Whosebug 规则,只允许一个接受的答案。所以,我决定检查他们的速度并接受最有效(最快)的答案。
为此,我人工创建了一个长度为 100,000 的字典列表:
check_length = 100000
list_example = []
for i in range(check_length):
list_example.append({f"companies_info_{i}": i})
然后,我定义了4个方法
Method name | Author |
---|---|
Method 1 | Me |
Method 2 | My own suggested solution described in the question |
Method 3 | @mozway |
Method 4 | @not a robot |
Method 5 | @Valdi_Bo |
我放弃了@Shubham Sharma 建议的最后一种称为 Pandas 方法 的方法,因为即使是 12 GB 的 RAM 也不够用。所以,显然这是最糟糕的方式。
包含100000个词典的列表迭代100次的结果如下:
Method name | Author | Results |
---|---|---|
Method 1 | Me | 58.829195756912235, 95% CI (58.436393856257794, 59.221997657566675) |
Method 2 | My own suggested solution described in the question | 28.41278486251831, 95% CI (28.330043057325845, 28.495526667710777) |
Method 3 | @mozway | 17.587587616443635, 95% CI (17.526133899890418, 17.649041332996852) |
Method 4 | @not a robot | 0.20350171089172364, 95% CI (0.19587073491102097, 0.2111326868724263) |
Method 5 | @Valdi_Bo | 15.767115621566772, 95% CI (15.721122343444568, 15.813108899688975) |
P.S。如果有人对我检查每种情况的速度的代码感兴趣,请看这里:
import pandas as pd
import numpy as np
import time
import math
# Method 1
def get_frame_method_1(l):
list_example_d = {"time": l}
df_1 = pd.DataFrame.from_dict(data=list_example_d, orient="columns")
index_list = []
for count, d in enumerate(df_1.time):
index_list.extend(list(d.keys()))
df_1.time[count]= list(d.values())[0]
df_1.index= index_list
return df_1
# Method 2
def get_frame_method_2(l):
df_list = []
for d in l:
d_df = pd.DataFrame.from_dict(data=d, orient="index", columns=["time"])
df_list.append(d_df)
df_2 = pd.concat(df_list, axis= 0)
return df_2
# Method 3
def get_frame_method_3(l):
df_3 = (pd.concat(map(pd.Series, l))
.to_frame('time')
)
return df_3
# Method 4
def get_frame_method_4(l):
# build a nested dict from list_example and build df
df_4 = pd.DataFrame.from_dict({k: {'time': v} for d in l for k,v in d.items()}, orient='index')
return df_4
# Method 5
def get_frame_method_5(l):
df_5 = pd.concat([ pd.Series(d.values(), index=d.keys())
for d in l ]).to_frame('time')
return df_4
check_length = 100000
list_example = []
for i in range(check_length):
list_example.append({f"companies_info_{i}": i})
total_time_1_d = {}
for i in range(100):
t_0 = time.time()
df_1 = get_frame_method_1(list_example)
t_1 = time.time()
df_2 = get_frame_method_2(list_example)
t_2 = time.time()
df_3 = get_frame_method_3(list_example)
t_3 = time.time()
df_4 = get_frame_method_4(list_example)
t_4 = time.time()
df_5= get_frame_method_5(list_example)
t_5 = time.time()
total_time_1_d[f"{i}"] = {"Method 1": (t_1-t_0), "Method 2": (t_2-t_1), "Method 3": (t_3-t_2), "Method 4": (t_4-t_3), "Method 5": (t_5-t_4)}
print(i)
total_time_df = pd.DataFrame.from_dict(data= total_time_1_d, orient="index")
for i in range(5):
print(f"Method {i+1}: Mean - {total_time_df.describe().iloc[1, i]}, 95% CI ({total_time_df.describe().iloc[1, i]-1.96*(total_time_df.describe().iloc[2, i])/math.sqrt((total_time_df.describe().iloc[0, i]))}, {total_time_df.describe().iloc[1, i]+1.96*(total_time_df.describe().iloc[2, i])/math.sqrt((total_time_df.describe().iloc[0, i]))})")