ORACLE one hot encoding:对所有可用列使用 PIVOT 运算符
Posted
技术标签:
【中文标题】ORACLE one hot encoding:对所有可用列使用 PIVOT 运算符【英文标题】:ORACLE one hot encoding: Use PIVOT operator for all available columns 【发布时间】:2020-09-04 15:05:55 【问题描述】:假设我有一个名为 t1 的表:
CLID PRODUCT
1 A
1 B
2 A
2 C
3 A
3 C
我需要在“产品”字段上进行某种单热编码。 在 Oracle 中,我们至少可以这样做:
select * from(
select clid, product
from t1
pivot(
count(product)
for product
in('A', 'B', 'C')
)
)
然后我们得到结果:
CLID A B C
1 1 1 0
2 1 0 1
3 1 0 1
但是当我们有大量产品(假设 1000 件)时就会出现问题,在这种情况下,将所有产品都置于 IN 状态会非常不方便。
所以我的问题是,是否有任何方法可以避免将所有可能的值放入“IN”? 如果没有这样的选项,那么也许有另一种方法可以在 Oracle sql(或 pl/sql?)中进行 one-hot-encoding?
【问题讨论】:
Oracle 可能不支持足够的列来支持您的查询。 您的最终结果应该是包含所有这些列的表,还是每个 CLID 的单个值('110'、'101'、'101'),还是其他?是否有单独的产品列表,可能在另一个表中? 在最终结果中,我需要 CLID 列中的值是唯一的(不是 1,1,2,3,而是 1,2,3)我还需要创建名为产品值的附加列(原始PRODUCT 字段需要删除)。在我的示例中,您可以看到我们获得了 3 个新列(A、B 和 C),并且这些列中的值仅为 1 或 0(1 代表产品的存在(列的名称表示我们正是哪个产品)对于某些 CLID值,0 代表不存在)。不,就我而言,我没有另一个包含产品列表的表格,但我可以创建它 什么会消耗这些数据?它对人类来说似乎不是很有用;但如果稍后将在其他地方处理它,那么您可以将其生成为 XML - 您可以使用in()
子句中的查询进行 XML 透视。否则,这可能是报告层应该做的事情。
嗯,实际上你是 100% 正确的,对人类来说它不是很有用:) 但是我需要完成这个过程才能将检索到的数据放入机器学习模型中,因为它们只适用于独特的案例数据。因此,为了捕获客户产品,我们需要为每个产品创建值为 1 或 0 的列。
【参考方案1】:
无论您的表中有多少不同的产品,您都可以使用 PL/SQL 匿名块自动构建查询,但您需要了解,您不能将超过 1000 个值放入数据透视子句中,因为您不能超过 1000 列。
我会做这样的事情(假设总是少于 1000 个值)
测试用例(创建表格和测试值)
SQL> create table t ( CLID number , PRODUCT varchar2(10) ) ;
Table created.
SQL> insert into t ( clid , product )
2 with x ( a , b ) as
(
select 1 , 'A' from dual union all
select 1 , 'B' from dual union all
select 2 , 'A' from dual union all
select 2 , 'C' from dual union all
select 3 , 'A' from dual union all
select 3 , 'C' from dual union all
select 4 , 'D' from dual union all
select 4 , 'E' from dual union all
select 5 , 'B' from dual union all
select 5 , 'C' from dual union all
select 5 , 'D' from dual union all
select 5 , 'E' from dual
)
select a , b from x ;
12 rows created.
SQL> commit ;
Commit complete.
PLSQL 构造
然后,无论有多少不同的产品,自动获取查询
set serveroutput on size unlimited lines 220 pages 0
declare
v_query clob;
out_string varchar2(100);
cursor c_ids
is
select distinct product, count(distinct(product)) over () tot_rows from t order by 1 asc;
procedure print_clob_to_output (p_clob in clob)
is
l_offset pls_integer := 1;
l_chars pls_integer;
begin
loop
exit when l_offset > dbms_lob.getlength(p_clob);
l_chars := dbms_lob.instr(p_clob, chr(10), l_offset, 1);
if l_chars is null or l_chars = 0 then
l_chars := dbms_lob.getlength(p_clob) + 1;
end if;
dbms_output.put_line(dbms_lob.substr(p_clob, l_chars - l_offset, l_offset));
l_offset := l_chars + 1;
end loop;
end print_clob_to_output;
begin
dbms_output.enable(null);
for item in c_ids
loop
if item.tot_rows >= 1000
then
raise_application_error(-20001,'Maximum number of 1000 columns are not allowed',true);
end if;
out_string := item.product;
if c_ids%rowcount = 1
then
v_query := 'select * from (';
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' select * ');
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' from t ');
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' pivot( ');
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' count(product) ');
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' for product in ( '''||out_string||''' , ');
elsif c_ids%rowcount < item.tot_rows then
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' '''||out_string||''' ,');
else
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' '''||out_string||''' ) ');
end if;
end loop;
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' ) )');
print_clob_to_output(v_query);
end;
/
执行
SQL> @query.sql
SQL> set serveroutput on size unlimited lines 220 pages 0
SQL> declare
2 v_query clob;
3 out_string varchar2(100);
4 cursor c_ids
5 is
6 select distinct product, count(distinct(product)) over () tot_rows from t order by 1 asc;
7 procedure print_clob_to_output (p_clob in clob)
8 is
9 l_offset pls_integer := 1;
10 l_chars pls_integer;
11 begin
12 loop
13 exit when l_offset > dbms_lob.getlength(p_clob);
14 l_chars := dbms_lob.instr(p_clob, chr(10), l_offset, 1);
15 if l_chars is null or l_chars = 0 then
16 l_chars := dbms_lob.getlength(p_clob) + 1;
17 end if;
18 dbms_output.put_line(dbms_lob.substr(p_clob, l_chars - l_offset, l_offset));
19 l_offset := l_chars + 1;
20 end loop;
21 end print_clob_to_output;
22 begin
23 dbms_output.enable(null);
24 for item in c_ids
25 loop
26 if item.tot_rows >= 1000
27 then
28 raise_application_error(-20001,'Maximum number of 1000 columns are not allowed',true);
29 end if;
30 out_string := item.product;
31 if c_ids%rowcount = 1
32 then
33 v_query := 'select * from (';
34 dbms_lob.append(v_query,''||chr(10)||'');
35 dbms_lob.append(v_query,' select * ');
36 dbms_lob.append(v_query,''||chr(10)||'');
37 dbms_lob.append(v_query,' from t ');
38 dbms_lob.append(v_query,''||chr(10)||'');
39 dbms_lob.append(v_query,' pivot( ');
40 dbms_lob.append(v_query,''||chr(10)||'');
41 dbms_lob.append(v_query,' count(product) ');
42 dbms_lob.append(v_query,''||chr(10)||'');
43 dbms_lob.append(v_query,' for product in ( '''||out_string||''' , ');
44 elsif c_ids%rowcount < item.tot_rows then
45 dbms_lob.append(v_query,''||chr(10)||'');
46 dbms_lob.append(v_query,' '''||out_string||''' ,');
47 else
48 dbms_lob.append(v_query,''||chr(10)||'');
49 dbms_lob.append(v_query,' '''||out_string||''' ) ');
50 end if;
51 end loop;
52 dbms_lob.append(v_query,''||chr(10)||'');
53 dbms_lob.append(v_query,' ) )');
54 print_clob_to_output(v_query);
55 end;
56 /
select * from (
select *
from t
pivot(
count(product)
for product in ( 'A' ,
'B' ,
'C' ,
'D' ,
'E' )
) )
PL/SQL procedure successfully completed.
SQL> select * from (
select *
from t
pivot(
count(product)
for product in ( 'A' ,
'B' ,
'C' ,
'D' ,
'E' )
) ) ;
CLID 'A' 'B' 'C' 'D' 'E'
---------- ---------- ---------- ---------- ---------- ----------
1 1 1 0 0 0
2 1 0 1 0 0
4 0 0 0 1 1
5 0 1 1 1 1
3 1 0 1 0 0
【讨论】:
以上是关于ORACLE one hot encoding:对所有可用列使用 PIVOT 运算符的主要内容,如果未能解决你的问题,请参考以下文章
如何从包含集合的 pandas 列转置和转换为“one-hot-encode”样式?
R语言使用caret包的dummyVars函数自动对训练数据集中的因子(factor)变量进行独热编码(one hot encoding)
从 scikit-learn 中的 one-hot-encoding 回溯分类特征?