PostgreSQL 相似人群圈选实践 - cube

相似人群分析在精准营销,推荐系统中的需求很多。

以音乐系统为例:根据用户对歌曲的行为进行打分

用户对歌曲的分数使用向量来表达,每个值代表一个歌曲的权重值,通过向量相似,可以得到一群相似的人群。

收集数据

根据用户行为给歌曲打分

单曲循环 分享 收藏 搜索 听完 没听过 跳过
5 4 3 2 1 0 -1

假设收集了以下数据

夜曲 七里香 简单爱 樱花草 安静了 记得要忘记 淘汰 烟花易冷 借口 江南
我自己 5 3 3 0 -1 2 5 4 1 -1
小明 4 5 2 1 0 3 2 0 1 1
小王 1 0 5 5 -1 5 0 0 1 2
小红 3 0 0 3 0 2 0 4 -1 -1
小白 0 0 0 -1 5 -1 5 0 4 1

欧式距离

欧氏距离(也被称为欧几里得距离)是空间中两点之间的直线距离,也称为直线距离或直线段距离。在二维平面上,欧氏距离可以使用勾股定理计算。在三维或更高维的空间中,它的计算方式也类似。

对于两个点(x1,x2)和(y1,y2)在二维空间上的欧氏距离计算公式为:

ini 复制代码
d=√(x1-y1)^2 +(x2-y2)^2

其中,√ 表示平方根。在更高维度的情况下,公式可以类似地扩展,例如在三维空间中 (x1,x2,x3)与(y1,y2,y3)的距离为:

scss 复制代码
d=√(x1-y1)^2 +(x2-y2)^2 +(x3-y3)^2

更多维度以此类推

根据欧式距离计算距离

makefile 复制代码
我自己: (5,3,3,0,-1,2,5,4,1,-1)
小明: (4,5,2,1,0,3,2,0,1,1)
小王:(1,0,5,5,-1,5,0,0,0,1)
小红:(3,0,0,3,0,2,0,4,-1,-1)
小白:(0,0,0,-1,5,-1,5,0,4,1)

根据上面欧式距离公式,我与小明、小王、小红、小白的欧式距离分别是

  • √38
  • √117
  • √61
  • √118

值越小表示距离越近,即相似度更高

实践-使用cube插件

sql 复制代码
-- 创建插件
create extension cube; 

-- 创建数据表
create table t_user_cube (
	uid int PRIMARY KEY,
	name varchar(20),
	c1 cube
);

--创建gist索引
create index idx_1 on t_user_cube using gist(c1);  

写入数据

sql 复制代码
insert into t_user_cube(uid,name,c1) values
(1,'我自己','(5,3,3,0,-1,2,5,4,1,-1)'),
(2,'小明','(4,5,2,1,0,3,2,0,1,1)'),
(3,'小王','(1,0,5,5,-1,5,0,0,0,1)'),
(4,'小红','(3,0,0,3,0,2,0,4,-1,-1)'),
(5,'小白','(0,0,0,-1,5,-1,5,0,4,1)'); 

单个特征搜索

通过单个特征值CUBE查询相似人群,以点搜群

sql 复制代码
-- 根据我自己的特征值匹配最相似的人
select * from t_user_cube  order by c1 <-> '(5,3,3,0,-1,2,5,4,1,-1)'; 

uid|name|c1                              |
---+----+--------------------------------+
  1|我自己 |(5, 3, 3, 0, -1, 2, 5, 4, 1, -1)|
  2|小明  |(4, 5, 2, 1, 0, 3, 2, 0, 1, 1)  |
  4|小红  |(3, 0, 0, 3, 0, 2, 0, 4, -1, -1)|
  3|小王  |(1, 0, 5, 5, -1, 5, 0, 0, 0, 1) |
  5|小白  |(0, 0, 0, -1, 5, -1, 5, 0, 4, 1)|

--剔除自己
select * from t_user_cube where uid !=1  order by c1 <-> '(5,3,3,0,-1,2,5,4,1,-1)'; 
select * from t_user_cube  order by c1 <-> '(5,3,3,0,-1,2,5,4,1,-1)'; 

uid|name|c1                              |
---+----+--------------------------------+
  2|小明  |(4, 5, 2, 1, 0, 3, 2, 0, 1, 1)  |
  4|小红  |(3, 0, 0, 3, 0, 2, 0, 4, -1, -1)|
  3|小王  |(1, 0, 5, 5, -1, 5, 0, 0, 0, 1) |
  5|小白  |(0, 0, 0, -1, 5, -1, 5, 0, 4, 1)|

多个特征搜索

通过多个特征值CUBE查询相似人群,以群搜群

scss 复制代码
-- 自己+小白的特征值
select * from t_user_cube  order by c1 <-> '[(5,3,3,0,-1,2,5,4,1,-1),(0,0,0,-1,5,-1,5,0,4,1)]';

uid|name|c1                              |
---+----+--------------------------------+
  1|我自己 |(5, 3, 3, 0, -1, 2, 5, 4, 1, -1)|
  5|小白  |(0, 0, 0, -1, 5, -1, 5, 0, 4, 1)|
  2|小明  |(4, 5, 2, 1, 0, 3, 2, 0, 1, 1)  |
  4|小红  |(3, 0, 0, 3, 0, 2, 0, 4, -1, -1)|
  3|小王  |(1, 0, 5, 5, -1, 5, 0, 0, 0, 1) |

cube最多支持100个维度

sql 复制代码
-- 创建生成随机CUBE的函数
create or replace function gen_rand_cube(int,int) returns cube as $$  
  select ('('||string_agg((random()*$2)::text, ',')||')')::cube from generate_series(1,$1);  
$$ language sql strict;

-- 尝试生成1000个维度
select gen_rand_cube(1000,10);  

SQL 错误 [22P02]: ERROR: invalid input syntax for cube
  Detail: A cube cannot have more than 100 dimensions.
  Where: SQL function "gen_rand_cube" statement 1

上面的例子以歌曲为例,根据向量匹配相似人群,cube只支持100个维度,如果歌曲超过100首怎么办呢?

可以换个思路,根据用户不同属性来打分,属性控制在100个以内,难点在于如何设计属性以及权重的变化,这个需要大家根据实际业务情况去思考了。

相关推荐
猿小喵14 分钟前
DBA之路,始于足下
数据库·dba
tyler_download23 分钟前
golang 实现比特币内核:实现基于椭圆曲线的数字签名和验证
开发语言·数据库·golang
weixin_449310841 小时前
高效集成:聚水潭采购数据同步到MySQL
android·数据库·mysql
CodingBrother1 小时前
MySQL 和 PostgreSQL 的使用案例
mysql·adb·postgresql
Cachel wood2 小时前
Github配置ssh key原理及操作步骤
运维·开发语言·数据库·windows·postgresql·ssh·github
standxy2 小时前
如何将钉钉新收款单数据高效集成到MySQL
数据库·mysql·钉钉
Narutolxy3 小时前
MySQL 权限困境:从权限丢失到权限重生的完整解决方案20241108
数据库·mysql
Venchill3 小时前
安装和卸载Mysql(压缩版)
数据库·mysql
Humbunklung3 小时前
一种EF(EntityFramework) MySQL修改表名去掉dbo前缀的方法
数据库·mysql·c#
PGCCC4 小时前
【PGCCC】postgresql 缓存池并发设计
数据库·缓存·postgresql