PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Postgresql k-nearest neighbor (KNN) no cubo multidimensional


PostgreSQL suporta operador de distância <-> e pelo que entendi, isso pode ser usado para analisar texto (com o módulo pg_trgrm) e geometria tipo de dados.

Eu não sei como você pode usá-lo com mais de 1 dimensão. Talvez você tenha que definir sua própria função de distância ou de alguma forma converter seus dados em uma coluna com texto ou tipo de geometria. Por exemplo, se você tiver uma tabela com 8 colunas (cubo de 8 dimensões):
c1 c2 c3 c4 c5 c6 c7 c8
 1  0  1  0  1  0  1  2

Você pode convertê-lo para:
c1 c2 c3 c4 c5 c6 c7 c8
 a  b  a  b  a  b  a  c

E então para a tabela com uma coluna:
c1
abababac

Então você pode usar (depois de criar gist índice ):
SELECT c1, c1 <-> 'ababab'
 FROM test_trgm 
 ORDER BY c1 <-> 'ababab';

Exemplo

Criar dados de amostra
-- Create some temporary data
-- ! Note that table are created in tmp schema (change sql to your scheme) and deleted if exists !
drop table if exists tmp.test_data;

-- Random integer matrix 100*8 
create table tmp.test_data as (
   select 
      trunc(random()*100)::int as input_variable_1,
      trunc(random()*100)::int as input_variable_2, 
      trunc(random()*100)::int as input_variable_3,
      trunc(random()*100)::int as input_variable_4, 
      trunc(random()*100)::int as input_variable_5, 
      trunc(random()*100)::int as input_variable_6, 
      trunc(random()*100)::int as input_variable_7, 
      trunc(random()*100)::int as input_variable_8
   from 
      generate_series(1,100,1)
);

Transforme dados de entrada em texto
drop table if exists tmp.test_data_trans;

create table tmp.test_data_trans as (
select 
   input_variable_1 || ';' ||
   input_variable_2 || ';' ||
   input_variable_3 || ';' ||
   input_variable_4 || ';' ||
   input_variable_5 || ';' ||
   input_variable_6 || ';' ||
   input_variable_7 || ';' ||
   input_variable_8 as trans_variable
from 
   tmp.test_data
);

Isso lhe dará uma variável trans_variable onde todas as 8 dimensões são armazenadas:
trans_variable
40;88;68;29;19;54;40;90
80;49;56;57;42;36;50;68
29;13;63;33;0;18;52;77
44;68;18;81;28;24;20;89
80;62;20;49;4;87;54;18
35;37;32;25;8;13;42;54
8;58;3;42;37;1;41;49
70;1;28;18;47;78;8;17

Em vez de || operador você também pode usar a seguinte sintaxe (mais curta, mas mais enigmática):
select 
   array_to_string(string_to_array(t.*::text,''),'') as trans_variable
from 
   tmp.test_data t

Adicionar índice
create index test_data_gist_index on tmp.test_data_trans using gist(trans_variable);

Test distanceNote:selecionei uma linha da tabela - 52;42;18;50;68;29;8;55 - e usou um valor ligeiramente alterado (42;42;18;52;98;29;8;55 ) para testar a distância. Claro, você terá valores completamente diferentes em seus dados de teste, porque é uma matriz RANDOM.
select 
   *, 
   trans_variable <->  '42;42;18;52;98;29;8;55' as distance,
   similarity(trans_variable, '42;42;18;52;98;29;8;55') as similarity,
from 
   tmp.test_data_trans 
order by
   trans_variable <-> '52;42;18;50;68;29;8;55';

Você pode usar o operador de distância <-> ou a função de similaridade. Distância =1 - Semelhança