在大型数据集(~3M 条目)上使用 PostgreSQL 进行特征工程

Posted

技术标签:

【中文标题】在大型数据集(~3M 条目)上使用 PostgreSQL 进行特征工程【英文标题】:Feature engineering using PostgreSQL on a large dataset (~3M entries) 【发布时间】:2016-08-19 18:24:11 【问题描述】:

我有一个包含约 300 万场国际象棋比赛的数据集(现有列包括玩家姓名、日期、结果和锦标赛名称)。我想用随机森林来预测棋局的结果。

为此,我想做一些特征工程。我认为有几个变量会成为强有力的预测因素,例如球员迄今为止在比赛中的成绩,比赛前90天的比赛次数。

列:

 - date DATE  
 - namew TEXT  
 - nameb TEXT  
 - whiterank INTEGER  
 - blackrank INTEGER  
 - tournament TEXT  
 - t_round INTEGER  
 - result REAL  
 - id BIGINT  
 - chess_data2_pkey(id)

指数:

game_index INDEX chess_data2 (namew ASC, tournament ASC, date ASC)

不幸的是,我的查询速度相当慢(我写了 14 个并在一个较小的数据集上对其进行了测试,甚至 1 个都没有在 8 天内完成)。下面是简化版,我2小时前放的,还是没有结果。

SELECT Sum(result) 
INTO   temp 
FROM   chess_data2 t1 
WHERE  id IN (SELECT t2.id 
              FROM   chess_data2 t2 
              WHERE  t1.tournament = t2.tournament 
                AND  t1.namew = t2.namew 
                AND  t1.date < t2.date) 

我的问题:

    我能否在 SQL 中加快这项工作的速度(在我的 i7-4710HQ 和 12gb 的 RAM 上,在不到 10 天的时间内完成 14 个类似的查询?)。也许通过事先明确排序? 还有其他方法可以更快地实现我的目标吗?我尝试使用 Python 中的循环天真地编写此代码,但性能更差,但我听说 C 更适合这些东西 - 但到底好多少?

我使用 Python 3.5 进行估计,使用 psycopg2 处理 SQL。

编辑:感谢大家的帮助。我设法成功地使用索引使一些查询变得非常快,例如这个:

# Number of points that the white player has so far accrued throughout the tournament
(SELECT coalesce(SUM(result),0) from chess_data2 t2
where (t1.namew = t2.namew) and t1.tournament = t2.tournament
and t1.date > t2.date  and t1.date < t2.date + 90)
+ SELECT coalesce(SUM(1-result),0) from chess_data2 t2
where (t1.namew = t2.nameb) and t1.tournament = t2.tournament
and t1.date > t2.date and t1.date < t2.date + 90 ) AS result_in_t_w
from chessdata2 t1

现在只需要大约 60 秒,这是可以接受的。但是,由于某种原因,像这样的计数选择需要半个多小时(我没有等待更长时间)来计算:

# Number of games that the white player has so far played in the tournament
(SELECT count(*) from chess_data t2 where (t1.namew = t2.namew) and
t1.tournament = t2.tournament and t1.date > t2.date and t1.date < t2.date + 90)
+ (SELECT coalesce(count(*),0) from chess_data2 t2
where (t1.namew = t2.nameb) and t1.tournament = t2.tournament
and t1.date > t2.date and t1.date < t2.date + 90) AS games_t_w from chess_data2 t1

我想我以错误的方式使用索引,但我不知道出了什么问题,它与以前基本相同,但我计算的不是对结果列求和,而是行总和......这是否有意义?

【问题讨论】:

在尝试提高查询性能时,您应该检查EXPLAIN ANALYZEREAD 我们可以查看您的数据库架构和定义的索引吗? @halfer 我添加了有关列和索引的信息(从 pycharm 复制),这是您所期望的吗? 是的,这很好。 id 上没有主键索引吗? 不,我们使用了“UPDATE chess_data2 SET id = DEFAULT”。所以我想我应该运行 ALTER TABLE chess_data2 ADD PRIMARY KEY (id)?就可以了。 【参考方案1】:

如果您想加快执行查询的速度,您可以创建用于连接的列索引(外键和使用 where 子句的列)。 但是添加索引会导致插入和更新速度变慢,并且需要增加磁盘空间。

【讨论】:

嘿,这确实有帮助!至少在某种程度上......我能够让 sum() 查询正常工作,但由于某种原因 count() 查询不能正常工作......知道如何继续(有关详细信息,请参阅我的编辑) ?【参考方案2】:

不知道你为什么使用那个IN。我认为您尝试简化查询并丢失了更多逻辑。

我相信这相当于

SELECT sum(result) INTO temp 
FROM chess_data2 t1 

你可能想要

SELECT tournament, namew, sum(result) 
FROM chess_data2 t1 
GROUP BY tournament, namew

SELECT tournament, namew, sum(result) 
FROM chess_data2 t1 
WHERE tournament = @tournament
  AND namew = @namew

【讨论】:

为了避免冗长的查询,我放了一个简化版本,但是 WHERE 子句中还有一个 t1.date 你检查EXPLAIN ANALYZE了吗?我们需要您提供数据库模式示例数据和预期结果,否则只是一个猜谜游戏。请阅读How-to-Ask 这里是START 了解如何提高问题质量并获得更好答案的好地方。 你也为你的表创建了索引吗? 好吧,我尽力让这个问题易于理解,当我是 SQL 的初学者时,这有点难 :) 我没有索引它,我几分钟前就开始了Abihabi87 的建议。我仍在与语法错误作斗争,但到目前为止,我做到了:CREATE INDEX game_index ON (namew, nameb,锦标赛, date) check HERE 我们不介意帮忙,但我们不是学校。您应该先尝试按照教程进行操作。

以上是关于在大型数据集(~3M 条目)上使用 PostgreSQL 进行特征工程的主要内容,如果未能解决你的问题,请参考以下文章

查找两个大型数据集之间的最近坐标

在大型数据集上训练异常检测模型并选择正确的模型 [关闭]

Ruby-on-Rails 3.2:导出包含大型数据集(100,000 条记录)的 CSV

无法将大型数据集加载到 h2 数据库中

在大型数据集上使用 rpart 包

有条件地匹配两个大型数据集的多列中的元素