将多个 dictionaries 列表合并为单个 DataFrame
数据小许
结论
先把多个字典列表合并为一个扁平列表,再统一创建 DataFrame。然后按 case_id 和 case_subject 分组计数,即可得到完整的结果表。
如果 rows_data 是嵌套列表,可以这样处理:
import pandas as pd
from itertools import chain
rows = list(chain.from_iterable(rows_data))
df = pd.DataFrame(rows)
out = (
df.assign(case_subject=df["case_subject"].str.split())
.explode("case_subject")
.groupby(["case_id", "case_subject"], as_index=False)
.size()
.rename(columns={"size": "Case_Subject_Split_Count"})
.sort_values(["case_id", "Case_Subject_Split_Count", "case_subject"],
ascending=[True, False, True])
.reset_index(drop=True)
)
print(out)
问题原因
示例数据实际上来自多个独立列表:
[
{"case_id": 22, "case_subject": "followup"},
...
]
[
{"case_id": 26, "case_subject": "c"},
...
]
如果程序在循环中依次生成这些列表,并且每次都执行:
df = pd.DataFrame(rows_data)
print(out)
程序就会创建并打印多个 DataFrame。应当先收集所有字典,等循环结束后再统一转换和统计。
另外,多个列表不能像示例中那样直接连续书写。实际数据应采用嵌套列表结构:
rows_data = [
[
{"case_id": 22, "case_subject": "followup"},
{"case_id": 22, "case_subject": "rma"},
],
[
{"case_id": 26, "case_subject": "app"},
{"case_id": 26, "case_subject": "request"},
],
]
使用列表推导式合并
如果不想引入 itertools,也可以用列表推导式展开数据:
rows = [
row
for group in rows_data
for row in group
]
df = pd.DataFrame(rows)
完整代码如下:
import pandas as pd
rows = [row for group in rows_data for row in group]
out = (
pd.DataFrame(rows)
.assign(case_subject=lambda x: x["case_subject"].str.split())
.explode("case_subject")
.value_counts(["case_id", "case_subject"])
.rename("Case_Subject_Split_Count")
.reset_index()
.sort_values(["case_id", "Case_Subject_Split_Count", "case_subject"],
ascending=[True, False, True])
.reset_index(drop=True)
)
print(out)
最终只会输出一个 DataFrame:
case_id case_subject Case_Subject_Split_Count
0 22 61555 1
1 22 followup 1
2 22 rma 1
3 22 ticket 1
4 26 app 1
5 26 c 1
6 26 ge 1
7 26 logs 1
8 26 request 1
9 30 refund 2
...
如果数据本来就是扁平列表
如果 rows_data 已经是下面这种结构:
rows_data = [
{"case_id": 22, "case_subject": "followup"},
{"case_id": 22, "case_subject": "rma"},
{"case_id": 26, "case_subject": "app"},
]
就不需要再次展开,可以直接创建 DataFrame:
df = pd.DataFrame(rows_data)
out = (
df.groupby(["case_id", "case_subject"], as_index=False)
.size()
.rename(columns={"size": "Case_Subject_Split_Count"})
)
如果每条 case_subject 都只有一个单词,.str.split() 和 .explode() 也可以省略。
在循环中收集数据
如果这些列表是在循环中生成的,可以先用 extend() 累积其中的字典:
all_rows = []
for item in source_data:
rows_data = create_rows(item)
all_rows.extend(rows_data)
df = pd.DataFrame(all_rows)
out = (
df.assign(case_subject=df["case_subject"].str.split())
.explode("case_subject")
.groupby(["case_id", "case_subject"], as_index=False)
.size()
.rename(columns={"size": "Case_Subject_Split_Count"})
)
这里要使用 extend(),而不是 append():
all_rows.extend(rows_data) # 加入列表中的每个字典
如果改用:
all_rows.append(rows_data)
all_rows 仍然是嵌套列表,之后还要再做一次扁平化处理。
注意事项
- 如果
case_subject可能包含多个以空格分隔的单词,需要保留.str.split().explode()。 - 如果每行的主题值都是一个不可拆分的整体,可以直接使用
groupby计数。 - 缺失的
case_subject默认不会作为普通分组参与统计。需要保留时,可以在groupby中设置dropna=False。 - 将
pd.DataFrame(...)和统计逻辑放到数据生成循环之外,确保它们只执行一次。
备注:内容仅供参考。
