BigQuery 计算值多列之间的重叠百分比

BigQuery Calculating Percent Overlap Between Values Multiple Columns

我对 SQL 和 bigquery 还很陌生,正在处理大约 140 万行的数据集。

我目前感兴趣的值是category_name(字符串),item_id(字符串)。我感兴趣的是计算 category_name 中每个值的不同 item_id(此列总共有 269 个不同值)。基本上在我的基础数据集中,每一行数据都包含一个 item_id 的实例,它显示在一个 category_name 中,其中 item_id 可以根据数量每天有多行那天出现了 category_name 秒。

我已经能够 运行 一个成功的查询,为 category_name 的每个值添加不同的 item_id 的新列,现在最终输出应该是什么我不知道如何计算 1 category_name 的不同 item_id 的百分比也出现在所有其他 category_name 中。所以基本上我正在寻找一个新列(如枢轴 table),它将计算匹配的 item_ids 2 category_names,然后将该计数除以总的不同 item_id 在 1 category_name 中。因此,基本上每个 category_name 将有 269 个新列,每一行将代表基础 category_name 与其他每个 category_name 的重叠百分比。

这是我的 table 目前我感兴趣的数据

category_name  |   item_id
---------------|------------
category1      |  item1
category2      |  item1
category3      |  item1
category1      |  item2
category4      |  item2
category1      |  item3
category5      |  item3
category5      |  item2
category6      |  item4
category3      |  item5
category3      |  item6
category1      |  item6
category2      |  item5
category1      |  item4

这是我当前的查询结果的样子

category_name  |  distinct_items
---------------|-----------------
category1      |  5
category2      |  2
category3      |  3
category4      |  1
category5      |  2
category6      |  1

这是我希望最终输出的样子:

category_name  | category1   |  category2  |   category3   |   category4   |  category5  |  category6
--------------------------------------------------------------------------------------------------------
category1      |   100%      |     20%     |      40%      |      20%      |     40%     |     20%
category2      |    50%      |     100%    |      100%     |       0%      |      0%     |     0%
category3      |    66.67%   |     66.67%  |      100%     |       0%      |      0%     |     0%
category4      |   100%      |      0%     |       0%      |      100%     |     100%    |     0%
category5      |   100%      |      0%     |       0%      |       50%     |     100%    |     0%
category6      |   100%      |      0%     |       0%      |       0%      |      0%     |    100%

本质上,category_name 的行值是当 category_name 是目标时,将它们的总数 distinct_items 与其他 category_name 进行比较,并找到 matches/total distinct_items 基于 item_ids。如果有另一种方法可以在没有枢轴 table 的情况下获得此输出,那也将不胜感激。上下文有 269 个 category_name 和 6525 个不同的 item_id。

如果有一个更简单的公式,我可以在 google Data Studio 中使用此聚合,因为 Data Studio 中的最终输出应该是散点图,其中 x 和 y 轴 category_names 和气泡是 % 重叠,所以基本上只是用散点图可视化枢轴 table 结果。如果我的描述和问题中的任何内容没有意义或需要更清楚地说明,请随时标记我并让我知道什么是令人困惑的。任何帮助是极大的赞赏!谢谢

您可以使用条件聚合:

select t.category_name,
       countif( t2.category_name = 'category1' ) / count(*) as category1,
       countif( t2.category_name = 'category2' ) / count(*) as category2,
       countif( t2.category_name = 'category3' ) / count(*) as category3,
       countif( t2.category_name = 'category4' ) / count(*) as category4,
       countif( t2.category_name = 'category5' ) / count(*) as category5
from t join
     t t2
     on t.item = t2.item
group by t.category_name;

如果将值放在行而不是列中,这会更简单:

select t.category_name, t2.category_name,
       count(*) / sum(count(*)) over (partition by t.category_name) as ratio
from t join
     t t2
     on t.item = t2.item
group by t.category_name, t2.category_name;

以下适用于 BigQuery 标准 SQL

第 1 步 - 动态生成查询文本,因此您无需手动输入所有 269 个类别...

#standardSQL
SELECT '''SELECT category_name, ''' || 
  STRING_AGG(DISTINCT
    ' MAX(IF(category_name2 = "' || category_name || '", percent, NULL)) AS ' || category_name
  ) || '''
FROM (
  SELECT t1.category_name, t2.category_name category_name2,
    ROUND(100 * COUNTIF(t1.item_id = t2.item_id) / COUNT(DISTINCT t1.item_id), 2) percent
  FROM `project.dataset.table` t1 
  CROSS JOIN `project.dataset.table` t2
  GROUP BY t1.category_name, t2.category_name
)
GROUP BY category_name
'''
FROM `project.dataset.table`

如果您 运行 上面针对问题中的样本数据 - 您将得到以下查询的扁平化版本

SELECT category_name, 
  MAX(IF(category_name2 = "category1", percent, NULL)) AS category1, 
  MAX(IF(category_name2 = "category2", percent, NULL)) AS category2, 
  MAX(IF(category_name2 = "category3", percent, NULL)) AS category3, 
  MAX(IF(category_name2 = "category4", percent, NULL)) AS category4, 
  MAX(IF(category_name2 = "category5", percent, NULL)) AS category5, 
  MAX(IF(category_name2 = "category6", percent, NULL)) AS category6 
FROM ( 
  SELECT t1.category_name, t2.category_name category_name2, 
  ROUND(100 * COUNTIF(t1.item_id = t2.item_id) / COUNT(DISTINCT t1.item_id), 2) percent 
  FROM `project.dataset.table` t1 
  CROSS JOIN `project.dataset.table` t2 
  GROUP BY t1.category_name, t2.category_name 
) 
GROUP BY category_name   

步骤 2 - 复制步骤 1 中的查询结果,然后 运行 将其作为查询 - 就是这样!

如果您将其应用于问题中的示例数据 - 输出将为

Row category_name   category1   category2   category3   category4   category5   category6    
1   category1       100.0       20.0        40.0        20.0        40.0        20.0     
2   category2       50.0        100.0       100.0       0.0         0.0         0.0  
3   category3       66.67       66.67       100.0       0.0         0.0         0.0  
4   category4       100.0       0.0         0.0         100.0       100.0       0.0  
5   category5       100.0       0.0         0.0         50.0        100.0       0.0  
6   category6       100.0       0.0         0.0         0.0         0.0         100.0         

注意 1:您可以使用您选择的任何客户端自动执行上述整个过程
注 2:在您的简化示例中,我主要处理数据。在您的实际情况下,您可能需要进行一些小的调整 - 如果您对此有任何疑问 - 请 post 新问题