知识库

根据某个条件对连续值进行分组


发布时间: 16 Feb 2018
上次修改日期: 13 Sep 2023

问题

如何对满足某个条件的连续值进行分组,或者换句话说,如何对属于同一时间段的所有值进行分组。

例如,根据连续出现负利润的天数创建天数组。如果连续 3 天利润为负数,这些天都将属于组“3”

环境

  • Tableau Desktop
  • 可选:Tableau Prep

答案

以下说明(使用示例数据集 Superstore)在工作簿“running count groups_v2021.1.twbx”中演示,可在右侧窗格下载。

这些说明会创建一个突出显示表,用于统计每个组中的时间段数。例如,数据集中有多少连续 3 天利润为负数的时间段?工作簿还包括创建交叉表视图和甘特图视图的说明。

选项 1:在 Tableau Desktop 中使用 PREVIOUS_VALUE()

我们可以检查是否当天满足条件(利润为负数),但前一天不满足条件,进而确定连续天数组的开始日期。使用 PREVIOUS_VALUE() 函数,我们可以为组中的每天重复开始日期值。然后,我们可以使用类似的过程,但从最旧的日期到最新的日期读取数据,进而确定结束日期。

创建计算

  1. 可选:使用与下列计算类似的计算创建一个名称类似于“利润无差异”的计算字段:
    ZN(LOOKUP(SUM([Profit]),0))
    
    
    注意:如果数据集缺少天数,此步骤将允许我们将缺少的天数视为零利润。如果跳过这一步,在接下来的所有步骤中使用 SUM([Profit]),而不是 [利润无差异]。
     
  2. 使用类似于以下计算的计算创建一个名称类似于“开始日期”的计算字段:
        IF [Profit no gaps] >= 0
    	THEN NULL
    	
    	ELSEIF LOOKUP([Profit no gaps],-1) >= 0
    	THEN MIN([Order Date])
    	
    	ELSE PREVIOUS_VALUE(#1/1/18#)
    	END
    
    
  3. 使用类似于以下计算的计算创建一个名称类似于“下一个利润值”的计算字段:
    
        LOOKUP([Profit no gaps],1)
        
  4. 使用类似于下列计算的计算创建一个名称类似于“结束日期”的计算字段:
    
    	IF [Profit no gaps] >= 0
    	THEN NULL
    	
    	ELSEIF [Next Profit Value] >= 0
    	THEN MIN([Order Date])
    	
    	ELSE PREVIOUS_VALUE(#1/1/18#)
    	END 
    
    
  5. 使用类似于下列计算的计算创建一个名称类似于“时间段中的天数”的计算字段:
    	
        DATEDIFF('day', [Start Date], [End Date]) + 1
        
  6. 使用类似于下列计算的计算创建一个名称类似于“时间段数”的计算字段:
    
        IF [Days in Streak] = 1 THEN
    	    WINDOW_SUM(
    	    IF [Days in Streak] = 1
    	    THEN COUNTD([Order Date])
    	    END
    	    )
    	ELSEIF [Days in Streak] = 2 THEN
    	    WINDOW_SUM(
    	    IF [Days in Streak] = 2
    	    THEN COUNTD([Order Date])
    	    END
    	    )
    	ELSEIF [Days in Streak] = 3 THEN
    	    WINDOW_SUM(
    	    IF [Days in Streak] = 3
    	    THEN COUNTD([Order Date])
    	    END
    	    )
    	ELSEIF ...
    	END / [Days in Streak]    
     

    注意:计算字段 [时间段数] 和 [每个时间段组只保留一个日期] 必须为一个时间段中每个可能的天数包含一个条件。如需查看详细原因,请查看文章使用聚合字段定义表计算的详细级别

  7. 使用类似于下列计算的计算创建一个名称类似于“每个时间段组只保留一个日期”的计算字段:
    
        MIN([Order Date]) = WINDOW_MIN(IF[Days in Streak] = 1 THEN [Start Date] END)
    	OR MIN([Order Date]) = WINDOW_MIN(IF[Days in Streak] = 2 THEN [Start Date] END)
    	OR MIN([Order Date]) = WINDOW_MIN(IF[Days in Streak] = 3 THEN [Start Date] END)
    	OR ...
    


构建突出显示表

  1. 将 [类别] 拖到“列”功能区
  2. 右键单击并将 [订单日期] 拖到“标记”卡上的“文本”
  3. 在“放置字段”对话框中,选择“MDY(Order Date)”并单击“确定”
  4. 将 [时间段天数] 拖到“标记”卡上的“标签”
  5. 右键单击“标签”上的 [时间段天数],并选择“编辑表计算 …”
  6. 在“表计算”对话框中,执行以下操作:
    1. 在“嵌套计算”下,选择“开始日期”
    2. 在“计算依据”下,选择“特定维度”
    3. 仅检查订单日期的月、日、年
    4. 在“嵌套计算”下,选择“利润无差异”
    5. 在“计算依据”下,选择“特定维度”
    6. 取消选中查所有维度
    7. 在“嵌套计算”下,选择“下一个利润值”
    8. 在“计算依据”下,选择“特定维度”
    9. 仅检查订单日期的月、日、年
    10. 在“嵌套计算”下,选择“结束日期”
    11. 在“计算依据”下,选择“特定维度”
    12. 仅检查订单日期的月、日、年
    13. 在“排序顺序”下拉列表中,选择“自定义”、”订单日期”、”最小值”、“升序”。
  7. 按住 Ctrl 并将 [时间段天数] 从“标签”拖到“行”功能区上
  8. 右键单击“行”功能区上的 [时间段天数],然后选择“离散”
  9. 将 [每个时间段组仅保留一天] 拖到“筛选器”功能区,并单击“确定”,关闭“筛选器”对话框
  10. 右键点击“筛选器”功能区上的 [每个时间段组仅保留一天] 并选择“编辑表计算…”
  11. 在“表计算”对话框中,执行以下操作:
    1. 重复步骤 6-1 到 6-13
    2. 在“嵌套计算”下,选择“每个时间段组仅保留一个日期”
    3. 在“计算依据”下,选择“特定维度”
    4. 仅检查订单日期的月、日、年
  12. 右键点击“筛选器”功能区上的 [每个时间段组仅保留一天] 并选择“编辑筛选器”。在“筛选器”对话框中,仅勾选“True”,并单击“确定”
  13. 按住 Ctrl 并将 [时间段天数] 拖到“标记”卡上
  14. 从“标记”卡上的下拉菜单中选择“方形”
  15. 单击“标记”卡上的“大小”,并将滑块调整到最右侧
  16. 使用类似于下列计算的计算创建一个名称类似于“空白”的计算字段:
    ""
    
    
  17. 将 [空白] 的一个副本拖到“行”功能区,将另一个副本拖到“列”功能区
  18. 右键单击“行”功能区上的 [Blank](空白),然后取消选中“显示标题”
 

选项 2:使用 Tableau Prep

创建 Prep 流程需要更多的前期工作,但从 Prep 输出构建视图比通过表计算构建视图要简单得多。“Grouping Consequtive days.tflx”流程可以演示下列步骤,可从右侧窗格下载。

创建 Prep 流程

  1. 连接到 Superstore 并将“订单”拖到画布中
  2. 可选:按照填补顺序数据中的空白填补每个类别顺序数据中的空白中的说明填补数据集中缺失的天数
  3. 创建一个名为“主要分支”的清理步骤
  4. 创建一个名为“仅保留字段”的聚合步骤
  5. 在“仅保留字段”聚合步骤中,将“类别”和“订单日期”添加到“分组字段”,将 SUM(Profit) 添加到“聚合字段”
  6. 创建一个名为“行号”的清理步骤
  7. 在“行号”清理步骤中,执行以下操作:
    1. 单击“创建计算字段…”,创建一个新的计算
    2. 将计算命名为“条件”。
    3. 为用于对天数进行分组的条件添加公式。例如,
      
      IF [Profit] < 0
      THEN 'negative'
      ELSE 'positive'
      END
      
      
    4. 使用与下列公式类似的公式创建一个名为“行号”的新计算字段
      
      { PARTITION [Category], [Condition] : { ORDERBY [Order Date] ASC : RANK_DENSE()}}
      
  8. 创建一个名为“行号 + 1”的清理步骤
  9. 在“行号 + 1”清理步骤中,执行以下操作:
    1. 使用与下列公式类似的公式创建一个名为“行号 + 1”的新计算字段 
      
      [行号] + 1
      
      
    2. 删除 [行号]
  10. 将“行号+ 1”清理步骤拖到“行号”清理步骤上,并放到“联接”上
  11. 在“联接 1”联接步骤中,执行以下操作:
    1. Tableau Prep 应该会在“条件 = 条件”上自动创建一个联接子句,如果没有创建,添加此联接子句
    2. 单击“已应用联接子句”部分左侧灰色侧面板中的加号
    3. 在“行号”菜单中选择“类别”
    4. 在“行号 + 1”菜单中选择“类别”
    5. 在“行号 = 行号 + 1”上添加另一个联接子句
    6. 在维恩图上,选择所有“行号”圆,以创建一个左联接
  12. 创建一个名为“开始日期”的清理步骤
  13. 在“开始日期”清理步骤中,执行以下操作:
    1. 单击 [类别],然后在按住 Ctrl 的同时单击 [类别-1],以选择两个字段
    2. 单击“合并字段”
    3. 合并 [条件] 和 [条件-1]
    4. 使用与下列公式类似的公式创建一个名为“开始日期”的新计算字段 
      
      IF ISNULL(DATEDIFF('day', [Order Date-1], [Order Date]))
      OR DATEDIFF('day', [Order Date-1], [Order Date]) > 1
      MIN([Order Date])\}
      END
      
      
    5. 单击“筛选器值...”
    6. 在“添加筛选器”对话框中,添加一个类似于 NOT ISNULL([Start Date]) 的公式,然后单击“保存”
    7. 使用与下列公式类似的公式创建一个名为“开始日期级别”的新计算字段 
      { PARTITION [Category], [Condition] : { ORDERBY [Start Date] ASC: RANK_DENSE()}}
      
      
    8. 删除 [行号]、[行号 + 1]、[订单日期]、[订单日期-1]
  14. 将鼠标悬停在“行号”清理步骤上,并单击该步骤的加号(不是嵌入在一个行中的加号),以创建一个名为“行号 - 1”的新清理步骤,它将创建一个单独的分支。
  15. 注意:步骤 15-19 和步骤 9-13 非常相似,但存在一些差异,它查找的是结束日期,而不是开始日期。请勿从“开始日期”分支复制计算字段,因为存在差异。 在“行号 - 1”清理步骤中,执行以下操作:
    1. 使用与下列公式类似的公式创建一个名为“开始日期级别”的新计算字段 
      
      [行号] - 1
      
      
    2. 删除 [行号]
  16. 将“行号 - 1”清理步骤拖到“行号”清理步骤上,并放到“联接”上
  17. 在“联接 2”联接步骤中,执行以下操作:
    1. 在“行号 = 行号 - 1;类别=类别;条件=条件”上创建联接子句
    2. 在维恩图上,选择所有“行号”圆,以创建一个左联接
  18. 创建一个名为“结束日期”的清理步骤
  19. 在“结束日期”清理步骤中,执行以下操作:
    1. 合并 [类别] 和 [类别-1] 
    2. 合并 [条件] 和 [条件-1]
    3. 使用与下列公式类似的公式创建一个名为“结束日期”的新计算字段
      
      IF ISNULL(DATEDIFF('day', [Order Date], [Order Date-1]))
      OR DATEDIFF('day', [Order Date], [Order Date-1]) > 1
      MIN([Order Date])\}
      END
      
      
    4. 通过类似于 NOT ISNULL([End Date]) 的公式添加一个筛选器
    5. 使用与下列公式类似的公式创建一个名为“结束日期级别”的新计算字段 
      
      { PARTITION [Category], [Condition] : { ORDERBY [End Date] ASC: RANK_DENSE()}}
      
      
    6. 删除 [行号]、[行号 + 1]、[订单日期]、[订单日期-1]
  20. 将“结束日期”清理步骤拖到“开始日期”清理步骤上并放到“联接”上
  21. 在“联接 3”中,为“条件=条件;类别=类别;结束日期级别=开始日期级别”创建联接子句
  22. 创建一个名为“清理”的清理步骤
  23. 在“清理”清理步骤中,执行以下操作:
    1. 合并 [类别] 和 [类别-1]
    2. 合并 [条件] 和 [条件-1]
    3. 使用与下列公式类似的公式创建一个名为“连续天数”的新计算字段 
      
      DATEDIFF('day', [Start Date],[End Date])+1
      
      
    4. 删除 [开始日期级别] 和 [结束日期级别]
  24. 将“清理”清理步骤拖到“主要分支”清理步骤上并放到“联接”上
  25. 在“联接 4”中,为“类别 = 类别; 订单日期 >= 开始日期; 订单日期 <= 结束日期”创建联接子句
  26. 创建一个名为“最终清理”的清理步骤
  27. 在“最终清理”清理步骤中,执行以下操作:
    1. 合并 [类别] 和 [类别-1]
  28. 可选:通过单击并拖动选择侧分支中的所有步骤,右键单击所有选中的步骤,然后选择“分组”

创建突出显示图表

  1. 将 [类别] 拖到“列”功能区
  2. 将 [连续天数] 拖到“行”功能区
  3. 右键单击“行”功能区上的 SUM(连续天数),并选择“维度”
  4. 右键单击“行”功能区上的 [连续天数],并选择“离散”
  5. 右键单击 [开始日期] 并将其拖到“文本”
  6. 在“放置字段”菜单中,选择 CNTD(开始日期),并单击“确定”
  7. 按住 Ctrl 并将 CNTD(开始日期) 从“标签”拖到“标记”卡上的“颜色”
  8. 在“标记”卡上的下拉菜单中选择“方形”
  9. 将 [条件] 拖到“筛选器”功能区
  10. 在“筛选器”对话框中,勾选负数,并单击“确定”
  11. 在显示“标准”的适合下拉菜单中选择“适合宽度”

其他信息

选项 1(使用 PREVIOUS_VALUE())注意事项
  • 如果不满足条件(利润为负数),则 [开始日期] 计算将返回 NULL。然后计算检查前一天是否满足条件,如果满足,则返回订单日期值。最后,如果当天和前一天都满足条件,则计算使用 PREVIOUS_VALUE() 在前一行返回来自此计算的日期。换句话说,Tableau Desktop 读取每一行(即每一天)时,此计算要么返回 NULL(该订单日期值),要么就会重复之前返回的订单日期值。
  • 此视图中的所有表计算都必须正确计算,才能显示预期的值。如需详细了解使用设置进行计算将如何改变表计算的结果,请参见使用表计算转换值
  • 与 LOOKUP() 不同,函数 PREVIOUS_VALUE() 将返回计算的最后一个值
选项 2(使用 Tableau Prep)注意事项
  • Prep 流程输出包含满足条件(利润为负数)和不满足条件的分组的开始日期。可以在“行号”清理步骤中添加一个筛选器,只保留 [Condition]='negative',以排除不满足条件的分组,否则需要将 [Condition] 筛选器添加到视图中。

     

使用表计算转换值
表计算函数
此文章是否已解决问题?