Вычисление скользящего среднего, при котором вы не всегда делите на общее количество - PullRequest
0 голосов
/ 03 августа 2020

Я пытаюсь вычислить скользящее среднее для игроков с битой в крикете. Любой, кто разбирается в этом виде спорта, знает, что среднее значение рассчитывается как забитые раны / подач, если только игрок с битой не выбывает. Если игрок с битой играет 2 иннинга и «не выбывает» в 1 из них, его среднее значение будет рассчитано как

runs scored innings 1 + runs scored innings 2 / 1

Если бы они были аута в обоих подачах, расчет будет

runs scored innings 1 + runs scored innings 2 / 2

Это достаточно просто, чтобы работать с общим средним значением, однако я хотел бы рассчитать его как скользящее среднее. Я сделал это перед тем, как использовать al oop и рассчитывать среднее значение для каждой строки индивидуально, но может ли кто-нибудь предложить способ сделать это с помощью любых встроенных функций?

Текущий пример кода:

with cte as (
select 
Innings_Player, 
Innings_Runs_Scored, 
Innings_Date, 
CASE WHEN Innings_Runs_Scored = "DNB" THEN null WHEN Innings_Runs_Scored LIKE "%*%" THEN REPLACE(Innings_Runs_Scored,"*","") ELSE Innings_Runs_Scored END AS RunsNum,
CASE WHEN Innings_Runs_Scored LIKE "%*%" THEN 1 ELSE 0 END AS NotOutFlag,
ROW_NUMBER() OVER (PARTITION BY Innings_Player ORDER BY Innings_Date) as RN
from TABLE
where Innings_Player = "JE Root"
AND Innings_Runs_Scored IS NOT NULL
ORDER BY Innings_Date
)
,cte2 as
(
select
 *,
   SUM(CAST(RunsNum AS INT64)) OVER (PARTITION BY Innings_Player ORDER BY RN) AS RunningTotal,
   AVG(CAST(RunsNum AS INT64)) OVER (PARTITION BY Innings_Player ORDER BY RN) AS RunningAvg,
 from cte
 where runsNum IS NOT NULL AND runsNum <> "TDNB"
)

select * from cte2

Результирующий набор данных:

набор данных

Значит, среднее неверное. Для скользящего среднего расчет для третьей строки должен быть innings_run_scored для первых трех строк, разделенных на 2, а не на 3, как вы можете видеть из NotOutFlag, что 3 иннинга в списке не были завершены.

Аналогично, строка 4 должна быть разделена на 3, строка 5 на 4, а затем, поскольку строка 6 также не вышла, строка 6 должна быть разделена на 4, строка 7 на 5 et c et c. Я думаю, уравнение будет

Innings_Run_Scored / Innings - Not Out Count

1 Ответ

0 голосов
/ 03 августа 2020

AVG в основном это SUM / COUNT Поскольку вы хотите изменить часть COUNT, я бы посоветовал отказаться от использования функции AVG. Вы можете подсчитать, используя SUM с CASE, чтобы подсчитать только те случаи, когда NotOutFlag равно 0

, поэтому строка

   AVG(CAST(RunsNum AS INT64)) OVER (PARTITION BY Innings_Player ORDER BY RN) AS RunningAvg,

станет

   SUM(CAST(RunsNum AS INT64)) OVER (PARTITION BY Innings_Player ORDER BY RN) 
/  SUM(CASE WHEN NotOutFlag = 0 THEN 1 ELSE 0 END) OVER (PARTITION BY Innings_Player ORDER BY RN)
AS RunningAvg,

Конечно, вам нужно будет добавить еще несколько logi c, чтобы избежать деления на 0.

CASE WHEN SUM(CASE WHEN NotOutFlag = 0 THEN 1 ELSE 0 END) OVER (PARTITION BY Innings_Player ORDER BY RN) = 0 
THEN 0 
ELSE 
SUM(CAST(RunsNum AS INT64)) OVER (PARTITION BY Innings_Player ORDER BY RN) 
/  
SUM(CASE WHEN NotOutFlag = 0 THEN 1 ELSE 0 END) OVER (PARTITION BY Innings_Player ORDER BY RN) 
END  AS RunningAvg,
...