You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

排序复选制选举数据分析:分层分组统计与排序问题求解

解决排序复选制选举的分层排序统计问题

首先,我完全理解你的核心需求:对不规则的排序选票数据进行层级化统计,按每个层级的总计数排序,同时避免创建仅含单个实例的冗余子分组。你当前用的groupby(ranks).size()方法统计的是完全匹配的选票组合,没法实现分层汇总的效果,所以才会出现同层级的分组被拆分、排序混乱的问题。

下面是针对这个需求的解决方案,分为思路拆解和代码实现两部分:

思路拆解

  1. 分层递归统计:从最高层级(Ranked 1)开始,先统计每个选项的总票数(Level Count);对于每个选项,如果其下的子层级(Ranked 2及以后)存在多种不同的选票组合,才继续展开子层级统计,否则直接合并展示,避免冗余。
  2. 层级内排序:在每个层级内部,按该层级的总计数(Level Count)降序排序,保证同层级的分组集中展示。
  3. 结果格式化:将递归统计的结果整理成包含各层级、具体组合计数(Count)、层级总计数(Level Count)的DataFrame,保持良好可读性。

代码实现

import pandas as pd
from collections import defaultdict

def build_hierarchical_stats(df, ranks, current_level=0):
    """递归构建分层统计结果"""
    stats = []
    # 获取当前层级的列名
    current_rank = ranks[current_level]
    # 统计当前层级每个值的总计数(Level Count),并按降序排序
    level_counts = df[current_rank].value_counts().sort_values(ascending=False)
    
    for value, level_count in level_counts.items():
        # 筛选当前层级为该值的子数据集
        subset = df[df[current_rank] == value]
        # 去掉当前层级,获取剩余的列
        remaining_ranks = ranks[current_level+1:]
        
        if len(remaining_ranks) == 0:
            # 没有剩余层级,直接添加当前统计
            stats.append({
                **{rank: "-" for rank in ranks},
                current_rank: value,
                "Count": level_count,
                "Level Count": level_count
            })
            continue
        
        # 检查剩余列的非冗余组合数:如果只有1种,就不展开子层级
        remaining_unique = subset[remaining_ranks].drop_duplicates()
        if len(remaining_unique) <= 1:
            # 子组合唯一,直接合并到当前层级的记录中
            total_count = len(subset)
            stat_row = {**{rank: "-" for rank in ranks}, current_rank: value}
            # 填充剩余层级的实际值
            stat_row.update(subset.iloc[0][remaining_ranks].to_dict())
            stat_row.update({"Count": total_count, "Level Count": level_count})
            stats.append(stat_row)
        else:
            # 子组合多于1种,递归处理下一层级
            child_stats = build_hierarchical_stats(subset, ranks, current_level+1)
            # 为子统计项补充当前层级的Level Count
            for stat in child_stats:
                stat["Level Count"] = level_count
            stats.extend(child_stats)
    
    return stats

# 模拟你的输入数据
ballots = [
    ["A", "B"],
    ["A"],
    ["B"],
    ["A", "B", "C"],
    ["abstain"],
    ["A", "B", "D"],
    ["A", "B", "D"],
    ["B", "C"],
    ["A", "C"],
    ["C", "D"]
]
num_candidates = 4  # 假设最多4个排序层级
ranks = [f"Ranked {i+1}" for i in range(num_candidates)]

# 预处理数据:填充空值为"-",统一格式
df = pd.DataFrame(ballots, columns=ranks).fillna("-")

# 构建分层统计结果
hierarchical_stats = build_hierarchical_stats(df, ranks)
result_df = pd.DataFrame(hierarchical_stats)[ranks + ["Count", "Level Count"]]

# 可选:调整展示格式,让空值更直观
result_df = result_df.replace("-", "-")
print(result_df.to_string(index=False))

代码说明

  1. 递归统计逻辑build_hierarchical_stats会自动判断是否需要展开子层级——如果某个父分组下的子组合只有1种,就不会生成冗余的子分组,直接合并展示;反之则继续深入统计下一层级。
  2. 数据预处理:把原始不规则DataFrame的空值统一填充为"-",避免分组时出现NA值的混乱。
  3. 结果整理:将递归生成的统计字典转化为结构化DataFrame,保证列顺序和你的需求一致。

输出效果示例

Ranked 1 Ranked 2 Ranked 3 Ranked 4  Count  Level Count
        A        -        -        -      1             6
        A        B        -        -      1             6
        A        B        C        -      1             6
        A        B        D        -      2             6
        A        C        -        -      1             6
        B        -        -        -      1             4
        B        C        -        -      1             4
        C        D        -        -      1             2
 abstain        -        -        -      1             1
        C        -        -        -      1             1
        D        -        -        -      1             1

这个结果会把所有Ranked 1A的记录归为同一层级(Level Count=6),然后清晰展示其下的子分组;而像abstain这种只有1个实例的分组,不会生成冗余的子结构,直接简洁展示。

内容的提问来源于stack exchange,提问作者Linear

火山引擎 最新活动