如何按id、id_2及全量label统计条目数?缺失类别补0
问题描述
现有如下结构的DataFrame:
id | id_2 | ... | label | -- | ----- | --- | ----- | 1 | x | ... | a | 1 | x | ... | a | 1 | x | ... | b | 1 | y | ... | a | 1 | z | ... | c | 1 | z | ... | b | 1 | z | ... | c | 2 | x | ... | a | 2 | x | ... | a | 2 | x | ... | b | 2 | x | ... | b | 2 | x | ... | b | 2 | x | ... | b |
需求是生成新的DataFrame,包含每个id、id_2与所有已知label的组合,对应条目计数;若某label在该id、id_2下不存在,计数补0,期望输出如下:
id | id_2 | label | count | -- | ---- | ----- | ----- | 1 | x | a | 2 | 1 | x | b | 1 | 1 | x | c | 0 | 1 | y | a | 1 | 1 | y | b | 0 | 1 | y | c | 0 | 1 | z | a | 0 | 1 | z | b | 1 | 1 | z | c | 2 | 2 | x | a | 2 | 2 | x | b | 4 | 2 | x | c | 0 |
直接使用groupBy(id, id_2, label).agg(count)无法得到缺失类别的0值,以下是具体实现思路:
实现思路
核心逻辑
要补全缺失组合的0值,关键是先构造出所有可能的(id, id_2, label)组合,再和原始聚合结果做关联补0。
步骤详解(以PySpark为例)
提取全局唯一label集合
先获取所有存在的label值,确保后续能覆盖所有类别:all_labels = df.select("label").distinct()提取唯一的(id, id_2)组合
从原始数据中得到所有不重复的(id, id_2)对:id_id2_pairs = df.select("id", "id_2").distinct()生成全量组合(笛卡尔积)
将(id, id_2)对和所有label做笛卡尔积,得到所有可能的组合:full_combinations = id_id2_pairs.crossJoin(all_labels)对原始数据做计数聚合
按(id, id_2, label)分组统计现有条目的数量:count_df = df.groupBy("id", "id_2", "label").agg(count("*").alias("count"))左连接补0
用全量组合表左连接聚合后的计数表,将缺失的count字段填充为0:result_df = full_combinations.join(count_df, on=["id", "id_2", "label"], how="left") \ .fillna({"count": 0}) \ .select("id", "id_2", "label", "count")
步骤详解(以Pandas为例)
提取全局唯一label集合
all_labels = df["label"].unique()生成全量组合
先获取唯一的(id, id_2)索引,再和所有label生成笛卡尔积:id_id2_index = df[["id", "id_2"]].drop_duplicates() full_combinations = id_id2_index.assign(key=1).merge(pd.DataFrame({"label": all_labels, "key":1}), on="key").drop("key", axis=1)原始数据聚合
count_df = df.groupby(["id", "id_2", "label"]).size().reset_index(name="count")左连接补0
result_df = full_combinations.merge(count_df, on=["id", "id_2", "label"], how="left").fillna({"count":0}).astype({"count": int})
内容的提问来源于stack exchange,提问作者user29329294
相关产品推荐
相关产品推荐

