Регрессионный анализ в MySQL
Введение
в моем проекте я экономлю FacebookPages и их счет, а также счет в каждой стране. У меня есть таблица для FacebookPages, одна для языков, одна для корреляции между страницей facebook и языком (и подсчетами подобных) и одной таблицей, которая сохраняет эти данные как историю. То, что я хочу сделать, - это получить страницу с самым сильным увеличением нравов за определенный период времени.
Данные для работы с
Я удаляю ненужную информацию из созданных запросов.
Таблица, содержащая все страницы facebook
CREATE TABLE `pages` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`facebook_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`facebook_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`facebook_likes` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Пример данных:
INSERT INTO `facebook_pages` (`id`, `facebook_id`, `facebook_name`, `facebook_likes`)
VALUES
(1, '552825254796051', 'Mesut Özil', 28593755),
(2, '134904013188254', 'Borussia Dortmund', 13213354),
(3, '310111039010406', 'Marco Reus', 12799627);
Таблица, содержащая все языки
CREATE TABLE `languages` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`language` varchar(5) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Примеры данных
INSERT INTO `languages` (`id`, `language`)
VALUES
(1, 'ID'),
(2, 'TR'),
(3, 'BR');
Таблица, содержащая корреляцию
CREATE TABLE `language_page_likes` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`language_id` int(10) unsigned NOT NULL,
`facebook_page_id` int(10) unsigned NOT NULL,
`likes` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
// Foreign key stuff
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Примеры данных
INSERT INTO `language_page_likes` (`id`, `language_id`, `facebook_page_id`)
VALUES
(1, 1, 1),
(2, 2, 1),
(3, 3, 1),
(47, 3, 2),
(51, 1, 2),
(53, 2, 2),
(92, 3, 3),
(95, 2, 3),
(97, 1, 3);
Таблица, содержащая историю
CREATE TABLE `language_page_likes_history` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`language_page_likes_id` int(10) unsigned NOT NULL,
`likes` int(11) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
// Foreign key stuff
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Примеры данных
INSERT INTO `language_page_likes_history` (`id`, `language_page_likes_id`, `likes`, `created_at`)
VALUES
(1, 1, 3272484, '2015-09-11 08:40:23'),
(132014, 1, 3272827, '2015-09-14 08:31:00'),
(2, 2, 1581361, '2015-09-11 08:40:23'),
(132015, 2, 1580392, '2015-09-14 08:31:00'),
(3, 3, 1467090, '2015-09-11 08:40:23'),
(132016, 3, 1467329, '2015-09-14 08:31:00'),
(47, 47, 828736, '2015-09-11 08:40:23'),
(132060, 47, 828971, '2015-09-14 08:31:00'),
(51, 51, 602747, '2015-09-11 08:40:23'),
(132064, 51, 603071, '2015-09-14 08:31:00'),
(53, 53, 545484, '2015-09-11 08:40:23'),
(132066, 53, 545092, '2015-09-14 08:31:00'),
(92, 92, 916570, '2015-09-11 08:40:24'),
(132105, 92, 917032, '2015-09-14 08:31:01'),
(95, 95, 537382, '2015-09-11 08:40:24'),
(132108, 95, 537395, '2015-09-14 08:31:01'),
(97, 97, 419175, '2015-09-11 08:40:24'),
(132110, 97, 419484, '2015-09-14 08:31:01');
Как вы можете видеть, я получил данные за 14 и 11 сентября. Теперь я хочу получить сайт с самым большим увеличением нравов. Прежде чем я сделал это с помощью столбца last_like_count, но проблема в том, что я не могу быть динамическим в диапазоне дат. С "нормальной" функцией регрессии я мог бы быть динамическим для каждого диапазона дат.
Поиск решений
То, что я уже успел сделать, заключалось в том, чтобы построить все существующие отношения
SELECT p.id, p.facebook_name, plh.likes, l.language FROM facebook_pages p
INNER JOIN language_page_likes pl ON pl.facebook_page_id = p.id
INNER JOIN language_page_likes_history plh ON plh.language_page_likes_id = pl.id
INNER JOIN languages l ON l.id = pl.language_id
WHERE pl.language_id = 5 OR pl.language_id = 46 OR pl.language_id = 68
С этим запросом я получаю все в истории системы для определенных языков. Но как бы я создал регрессионный анализ в этой части?
Я уже нашел эту ссылку здесь
Определение тенденции с помощью SQL-запроса
но мои навыки математики и MySQL недостаточно высоки, чтобы перевести SQL в MySQL. Любая помощь?
Ответы
Ответ 1
Это может быть то, что вы ищете:
SELECT SUM((X-AVG_X)*(Y-AVG_Y)) / SUM((X-AVG_X)*(X-AVG_X)) AS Slope,
PageId, LanguageId
FROM
(
SELECT Q0.Y,
Q0.X,
Q1.AVG_Y,
Q1.AVG_X,
Q1.PageId,
Q1.LanguageId
FROM (SELECT T0.likes AS Y,
UNIX_TIMESTAMP(T0.created_at) AS X,
T1.facebook_page_id AS PageId,
T1.language_id AS LanguageId
FROM language_page_likes_history T0 INNER JOIN
language_page_likes T1 ON
(T0.language_page_likes_id = T1.id)
WHERE T0.created_at > '2015-09-11 00:00:00' AND
T0.created_at < '2015-09-15 00:00:00') Q0 INNER JOIN
(SELECT AVG(T2.likes) AS AVG_Y,
AVG(UNIX_TIMESTAMP(T2.created_at)) AS AVG_X,
T3.facebook_page_id AS PageId,
T3.language_id AS LanguageId
FROM language_page_likes_history T2 INNER JOIN
language_page_likes T3 ON
(T2.language_page_likes_id = T3.id)
WHERE T2.created_at > '2015-09-11 00:00:00' AND
T2.created_at < '2015-09-15 00:00:00'
GROUP BY T3.facebook_page_id, T3.language_id) Q1
ON (Q0.PageId = Q1.PageId) AND (Q0.LanguageId = Q1.LanguageId)
) Q2
GROUP BY PageId, LanguageId
ORDER BY Slope DESC
Он возвращает наклон линейной регрессии на страницу и язык. Столбец Slope представляет количество понравившихся в секунду. В ваших образцовых данных количество симпатий уменьшается для двух случаев. Я не знаю почему. Результат должен выглядеть следующим образом. Оператор SQL проверен, и я проверил два вычисления строк вручную для правильного вывода.
| Slope | PageId | LanguageId |
|-----------------|--------|------------|
| 0.001786287345 | 3 | 3 |
| 0.001326183029 | 1 | 1 |
| 0.001252720995 | 2 | 1 |
| 0.001194724653 | 3 | 1 |
| 0.000924075055 | 1 | 3 |
| 0.000908609364 | 2 | 3 |
| 0.000050263497 | 3 | 2 |
| -0.001515637747 | 2 | 2 |
| -0.003746563717 | 1 | 2 |
Может возникнуть проблема, если в таблицах нет данных. Поэтому, возможно, необходимо добавить ISNULL-проверки.
Когда вы только хотите знать абсолютные значения, это проще. Вы можете принять следующее утверждение:
SELECT PageId, LanguageId,
(likes_last_in_period - likes_before_period) AS Likes
FROM
(SELECT T1.facebook_page_id AS PageId,
T1.language_id AS LanguageId,
(SELECT likes
FROM language_page_likes_history
WHERE created_at < '2015-09-12 00:00:00' AND
language_page_likes_id = T1.id
ORDER BY created_at DESC LIMIT 1) likes_before_period,
(SELECT likes
FROM language_page_likes_history
WHERE created_at >= '2015-09-12 00:00:00' AND
language_page_likes_id = T1.id
ORDER BY created_at ASC LIMIT 1) likes_first_in_period,
(SELECT likes
FROM language_page_likes_history
WHERE created_at <= '2015-09-15 00:00:00' AND
language_page_likes_id = T1.id
ORDER BY created_at DESC LIMIT 1) likes_last_in_period,
(SELECT likes
FROM language_page_likes_history
WHERE created_at > '2015-09-15 00:00:00' AND
language_page_likes_id = T1.id
ORDER BY created_at ASC LIMIT 1) likes_after_period
FROM language_page_likes T1) Q0
ORDER BY Likes DESC
который имеет 4 подзапроса. Вам нужны только два, которые вам нужно выбрать. Я решил использовать количество понравившихся людей до периода и последнего числа симпатий, которое находится в периоде для вычисления разницы. Результат выглядит следующим образом:
| PageId | LanguageId | Likes |
|--------|------------|-------|
| 3 | 3 | 462 |
| 1 | 1 | 343 |
| 2 | 1 | 324 |
| 3 | 1 | 309 |
| 1 | 3 | 239 |
| 2 | 3 | 235 |
| 3 | 2 | 13 |
| 2 | 2 | -392 |
| 1 | 2 | -969 |
Ответ 2
Вот что я мог придумать прямо сейчас. Я не могу правильно протестировать этот запрос, потому что теперь у меня нет времени на создание этих структур таблиц на одной из тестовых страниц веб-сайта. Но я думаю, что даже если он не работает, он может указать вам в правильном направлении.
select
id,
new_date,
max(increase)
from (
select
dg.id,
dg.date new_date,
dg.sum - (select sum from dg where dg.date = date_format((date_sub(str_to_date(new_date, '%Y-%m-%d') 1 DAY), '%Y-%m-%d') increase
from (
select
language_pages_likes_id id,
date_format(created_at, '%Y%-m$-%d') date,
sum(likes) likes_sum
from
language_page_likes_history lplh
group by
language_page_likes_id,
date_format(created_at, '%Y%-m$-%d')
) day_grouping dg
) calculate_increases
Надеюсь, это поможет. Позже, когда я смогу, я буду дополнительно тестировать и улучшать этот запрос.