将 table 转换为多行的单热编码
Transform table to one-hot encoding for many rows
我有一个 SQL table 格式如下:
ID Cat
1 A
1 B
1 D
1 F
2 B
2 C
2 D
3 A
3 F
现在,我想创建一个 table,每行一个 ID,一行中有多个 Cat。我想要的输出如下所示:
ID A B C D E F
1 1 1 0 1 0 1
2 0 1 1 1 0 0
3 1 0 0 0 0 1
我发现:
但是,我有 1000 多个 Cat,所以我正在寻找代码来自动编写此代码,而不是手动编写。谁能帮我解决这个问题?
BigQuery 没有标准 SQL 的动态列,但根据您下一步要执行的操作,可能有一种方法可以使它更容易。
以下代码示例按 ID 对 Cat 进行分组,并使用 JavaScript 函数进行 one-hot 编码和 return JSON 字符串。
CREATE TEMP FUNCTION trans(cats ARRAY<STRING>)
RETURNS STRING
LANGUAGE js
AS
"""
// TODO: Doing one hot encoding for one cat and return as JSON string
return "{a:1}";
"""
;
WITH id_cat AS (
SELECT 1 as ID, 'A' As Cat UNION ALL
SELECT 1 as ID, 'B' As Cat UNION ALL
SELECT 1 as ID, 'C' As Cat UNION ALL
SELECT 2 as ID, 'A' As Cat UNION ALL
SELECT 3 as ID, 'C' As Cat)
SELECT ID, trans(ARRAY_AGG(Cat))
FROM id_cat
GROUP BY ID;
首先让我将您粘贴的数据转换为实际的 table:
WITH data AS (
SELECT REGEXP_EXTRACT(data2, '[0-9]') id, REGEXP_EXTRACT(data2, '[A-Z]') cat
FROM (
SELECT SPLIT("""1 A
1 B
1 D
1 F
2 B
2 C
2 D
3 A
3 F""", '\n') AS data1
), UNNEST(data1) data2
)
SELECT * FROM data
(下次试试分享一个table)
现在我们可以进行一些手动 1-hot 编码:
SELECT id
, MAX(IF(cat='A',1,0)) cat_A
, MAX(IF(cat='B',1,0)) cat_B
, MAX(IF(cat='C',1,0)) cat_C
FROM data
GROUP BY id
现在我们要编写一个脚本来自动创建我们想要的列:
SELECT STRING_AGG(FORMAT("MAX(IF(cat='%s',1,0))cat_%s", cat, cat), ', ')
FROM (
SELECT DISTINCT cat
FROM data
ORDER BY 1
)
这会生成一个字符串,您可以将其复制粘贴到查询中,1-hot 会对您的 arrays/rows:
进行编码
SELECT id
,
MAX(IF(cat='A',1,0))cat_A, MAX(IF(cat='B',1,0))cat_B, MAX(IF(cat='C',1,0))cat_C, MAX(IF(cat='D',1,0))cat_D, MAX(IF(cat='F',1,0))cat_F
FROM data
GROUP BY id
这正是问题所要求的。您可以使用 SQL 生成 SQL,但您需要使用该结果编写一个新查询。
我有一个 SQL table 格式如下:
ID Cat
1 A
1 B
1 D
1 F
2 B
2 C
2 D
3 A
3 F
现在,我想创建一个 table,每行一个 ID,一行中有多个 Cat。我想要的输出如下所示:
ID A B C D E F
1 1 1 0 1 0 1
2 0 1 1 1 0 0
3 1 0 0 0 0 1
我发现:
但是,我有 1000 多个 Cat,所以我正在寻找代码来自动编写此代码,而不是手动编写。谁能帮我解决这个问题?
BigQuery 没有标准 SQL 的动态列,但根据您下一步要执行的操作,可能有一种方法可以使它更容易。
以下代码示例按 ID 对 Cat 进行分组,并使用 JavaScript 函数进行 one-hot 编码和 return JSON 字符串。
CREATE TEMP FUNCTION trans(cats ARRAY<STRING>)
RETURNS STRING
LANGUAGE js
AS
"""
// TODO: Doing one hot encoding for one cat and return as JSON string
return "{a:1}";
"""
;
WITH id_cat AS (
SELECT 1 as ID, 'A' As Cat UNION ALL
SELECT 1 as ID, 'B' As Cat UNION ALL
SELECT 1 as ID, 'C' As Cat UNION ALL
SELECT 2 as ID, 'A' As Cat UNION ALL
SELECT 3 as ID, 'C' As Cat)
SELECT ID, trans(ARRAY_AGG(Cat))
FROM id_cat
GROUP BY ID;
首先让我将您粘贴的数据转换为实际的 table:
WITH data AS (
SELECT REGEXP_EXTRACT(data2, '[0-9]') id, REGEXP_EXTRACT(data2, '[A-Z]') cat
FROM (
SELECT SPLIT("""1 A
1 B
1 D
1 F
2 B
2 C
2 D
3 A
3 F""", '\n') AS data1
), UNNEST(data1) data2
)
SELECT * FROM data
现在我们可以进行一些手动 1-hot 编码:
SELECT id
, MAX(IF(cat='A',1,0)) cat_A
, MAX(IF(cat='B',1,0)) cat_B
, MAX(IF(cat='C',1,0)) cat_C
FROM data
GROUP BY id
现在我们要编写一个脚本来自动创建我们想要的列:
SELECT STRING_AGG(FORMAT("MAX(IF(cat='%s',1,0))cat_%s", cat, cat), ', ')
FROM (
SELECT DISTINCT cat
FROM data
ORDER BY 1
)
这会生成一个字符串,您可以将其复制粘贴到查询中,1-hot 会对您的 arrays/rows:
进行编码SELECT id
,
MAX(IF(cat='A',1,0))cat_A, MAX(IF(cat='B',1,0))cat_B, MAX(IF(cat='C',1,0))cat_C, MAX(IF(cat='D',1,0))cat_D, MAX(IF(cat='F',1,0))cat_F
FROM data
GROUP BY id
这正是问题所要求的。您可以使用 SQL 生成 SQL,但您需要使用该结果编写一个新查询。