MYSQL 按组加权平均

Posted

技术标签:

【中文标题】MYSQL 按组加权平均【英文标题】:MYSQL weighted average by group 【发布时间】:2016-11-08 00:30:21 【问题描述】:

我有一个mysql表,结构如下

| Field          | Type         | 
+----------------+--------------+
| Data           | timestamp    | 
| ticker         | varchar(250) |                                        
| sentiment      | double       |                                            
| numberofTweets | int(11)      |

而且有 70 个不同的代码,我需要计算每个代码的加权平均值。

我正在做以下事情:

select ticker, round(sum(sentiment)/sum(numberofTweets),2) as wAverage
from sentiment
WHERE ticker = 'GBP/USD'
order by data desc
limit 288;

有没有办法在一个查询中处理所有代码?

提前谢谢!

编辑 1:

我需要为每个股票代码使用 288 条记录来进行计算,所以使用 GROUP BY clausule 将不起作用!

【问题讨论】:

整体平均还是每个股票? 对于每个代码 使用GROUP BY ticker 而不是WHERE ... Paul 使用 'group by limit 288' 它会为每个代码选择 288 个最后的记录然后进行计算? 否 :-) - 你想要每个代码最近 288 行的平均值吗? 【参考方案1】:

为了简化您的问题,我使用下表:

CREATE TABLE `items` (
    `id` MEDIUMINT(8) UNSIGNED NOT NULL,
    `group_id` TINYINT(3) UNSIGNED NOT NULL,
    `val` DOUBLE UNSIGNED NOT NULL DEFAULT '0',
    PRIMARY KEY (`id`),
    INDEX `group_id` (`group_id`)
) ENGINE=InnoDB;

测试数据包含 100 个组,每个组平均有 1000 个项目(总共 100K 行)。

set @num_rows = 100000;
set @per_group = 1000;
set @num_groups = @num_rows div @per_group;

insert into items (id, group_id, val)
    select seq as id
        , floor(rand(1)*@num_groups) + 1 as group_id
        , rand(2) as val
    from seq_1_to_1000000
    where seq <= @num_rows
;

任务:为每个group_id 获取最新288 行的val 总和。

如果没有每组 288 行的要求,那就是

select group_id, sum(val)
from items
group by group_id

但您首先需要将数据集限制为每组 288 行。搜索“mysql top n per group”,你会发现很多关于SO的相关问题。

大部分答案都会使用会话变量:

select group_id, sum(val)
from (
    select i.group_id, i.val,
        case when i.group_id = @group 
            then @rn:=@rn+1
            else @rn:=1
        end rn,
        @group := i.group_id 
    from items i
    cross join (select @rn := null, @group := null) init_vars
    order by i.group_id, i.id desc
) t
where rn <= 288
group by group_id
order by group_id

查询时间:62 - 78 毫秒(我的客户没有显示确切的数字)。但是 - 使用此解决方案您依赖于引擎的执行顺序,这可能会在未来的版本中发生变化。

其他一些答案使用自联接:

select group_id, sum(val)
from (
    select i.group_id, i.val
    from items i
    join items i1
        on  i1.group_id = i.group_id
        and i1.id >= i.id
    group by i.id
    having count(*) <= 288
) t
group by group_id
order by group_id

但只有小团体(平均团体规模

SUBSTRING_INDEX(GROUP_CONCAT(...), ...) 也有一个“技巧”,可能需要针对大型组调整 @@group_concat_max_len。 但我更喜欢这个:

select i.group_id, sum(i.val)
from items i
where i.id >= coalesce((
    select i1.id
    from items i1
    where i1.group_id = i.group_id
    order by i1.id desc
    limit 1
    offset 287
), 0)
group by i.group_id
order by i.group_id

它首先在相关子查询中找到每个组的第 288 个最高 id,并且只使用具有更高或相等 id 的行。如果一个组的行数少于 288,则将使用所有行(id >= 0)。 查询时间:78 - 94 毫秒。

根据你的问题调整它,你会得到:

select s.ticker, round(sum(sentiment)/sum(numberofTweets),2) as wAverage
from sentiment s
where s.data >= coalesce((
    select s1.data 
    from sentiment s1
    where s1.ticker = s.ticker
    order by s1.data desc
    limit 1
    offset 287
), from_unixtime(0))
group by s.ticker
order by s.ticker

请注意,如果您按非唯一列对结果进行排序,则限制结果集的定义不明确。因此,如果两个时间戳相等,它可能会使用 289 行或更多行。最好使用 AUTO_INCREMENT PRIMARY KEY。

【讨论】:

Paul 很抱歉耽搁了这么久,今晚我会试试我和你学到的东西! tks

以上是关于MYSQL 按组加权平均的主要内容,如果未能解决你的问题,请参考以下文章

R中按组月的平均温度

如何在 R 的列表中按组获取平均值

在R中按组应用滚动平均值

如何在ggplot的箱线图中按组绘制平均值

按组SAS保存平均值

如何从 sql 中的 2 个表中按组聚合和计算平均值?