如何按Name分组统计表格中category的转换段数?
实现按Name分组统计Category转换段数
需求说明
需要按Name分组统计表格内category的转换段数,核心规则是统计每组内连续相同category的独立段数:
- Name为B时,category序列是
Good→Good→Good→Bad,连续相同的段共2段,对应转换段数为2; - Name为A时,category序列是
Good→Good→Moderate→Good→Moderate→Bad→Bad,连续相同的段共5段,对应转换段数为5。
输入表格
| Name | order no | category |
|---|---|---|
| A | 1 | Good |
| A | 2 | Good |
| A | 3 | MODERATE |
| A | 4 | Good |
| A | 5 | MODERATE |
| A | 6 | Bad |
| A | 7 | Bad |
| B | 1 | Good |
| B | 2 | Good |
| B | 3 | Good |
| B | 4 | BAD |
期望输出表格
| Name | category_transition_count |
|---|---|
| A | 5 |
| B | 2 |
实现方案1:Python Pandas
这是处理表格数据最便捷的方式之一,步骤清晰易理解:
import pandas as pd # 加载数据(如果是从CSV/Excel读取,替换成pd.read_csv/pd.read_excel即可) data = [ ["A", 1, "Good"], ["A", 2, "Good"], ["A", 3, "MODERATE"], ["A", 4, "Good"], ["A", 5, "MODERATE"], ["A", 6, "Bad"], ["A", 7, "Bad"], ["B", 1, "Good"], ["B", 2, "Good"], ["B", 3, "Good"], ["B", 4, "BAD"] ] df = pd.DataFrame(data, columns=["Name", "order no", "category"]) # 1. 统一category大小写,避免大小写差异导致误判 df["category"] = df["category"].str.lower() # 2. 标记每组内的连续category段落:同一Name下,当前行与上一行category不同则段落编号+1 df["transition_group"] = df.groupby("Name")["category"].apply(lambda x: x.ne(x.shift()).cumsum()) # 3. 按Name分组统计段落数量 result = df.groupby("Name")["transition_group"].nunique().reset_index() result.columns = ["Name", "category_transition_count"] # 输出结果 print(result)
执行后会直接输出期望的结果:
Name category_transition_count 0 A 5 1 B 2
逻辑说明
str.lower():把所有category转成小写,解决"MODERATE"和"moderate"被误判为不同类别的问题;x.ne(x.shift()):对比当前行和上一行的category是否不同,返回布尔值;cumsum():对布尔值累加,相同连续category会得到同一个段落编号,不同段落编号自动递增;nunique():统计每组内的唯一段落编号数量,也就是我们要的转换段数。
实现方案2:SQL(适用于数据库存储的数据)
如果数据存在MySQL、PostgreSQL等数据库中,可以用窗口函数实现:
WITH transition_groups AS ( SELECT Name, -- 统一category大小写 LOWER(category) AS normalized_category, -- 标记连续段落:同一Name下,当前行与上一行category不同则+1 SUM( CASE WHEN LOWER(category) = LOWER(LAG(category) OVER (PARTITION BY Name ORDER BY `order no`)) THEN 0 ELSE 1 END ) OVER (PARTITION BY Name ORDER BY `order no`) AS group_id FROM your_table_name ) SELECT Name, COUNT(DISTINCT group_id) AS category_transition_count FROM transition_groups GROUP BY Name;
执行这条SQL后,会直接返回期望的分组统计结果。
内容的提问来源于stack exchange,提问作者Mathew
相关产品推荐
相关产品推荐

