PAYATHON 2026

将多个 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(...) 和统计逻辑放到数据生成循环之外,确保它们只执行一次。

备注:内容仅供参考。