我有一个包含大部分为空值的时间序列数据的表,我想用最后一个已知值填充所有空值。
我有一些解决方案,但它们比DataFrame.fillna(method='ffill')在 Pandas 中执行等效操作要慢得多。
我正在使用的代码/数据的简化版本:
select d.[date], d.[price],
(select top 1 p.price from price_table p
where p.price is not null and p.[date] <= p.[date]
order by p.[date] desc) as ff_price
from price_table d
Run Code Online (Sandbox Code Playgroud)
生产表
date price ff_price
---------- ----- --------
2016-07-11 0.79 0.79
2016-07-12 NULL 0.79
2016-07-13 NULL 0.79
2016-07-14 0.69 0.69
2016-07-15 NULL 0.69
...
2016-09-21 0.88 0.88
...
Run Code Online (Sandbox Code Playgroud)
我有 > 1 亿行,所以这需要很长时间。
这看起来像是一个“经典”的缺口和岛屿问题。假设您没有使用 2008 或之前的版本(所有(几乎)完全不受支持),这应该会得到您想要的结果:
WITH CTE AS(
SELECT [date],
price,
COUNT(CASE WHEN price IS NOT NULL THEN 1 END) OVER (ORDER BY [date]
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Grp
FROM price_table p)
SELECT [date],
price,
MIN(price) OVER (PARTITION BY grp) AS ff_price
FROM CTE;
Run Code Online (Sandbox Code Playgroud)
假设您的列是DATE且价格是DECIMAL(5,2),请测试此方法:
SELECT
P.[date],
P.[price],
ff_price = CONVERT(
DECIMAL(5,2), -- Original price datatype
SUBSTRING(
MAX(
CAST(P.[date] AS BINARY(3)) + -- 3: datalength of P.[date] column
CAST(P.[price] AS BINARY(5)) -- 5: datalength of P.[price] column
) OVER (ORDER BY P.[date] ROWS UNBOUNDED PRECEDING),
4, -- Position to start that's not the binary part of the date
5))-- Characters that compose the binary of the original price datatype
FROM
price_table AS P
Run Code Online (Sandbox Code Playgroud)
这是我针对类似问题实现的解决方案,您可以在这里找到详尽的解释。这种方法很好的原因是它不需要显式排序,只要您有一个索引即可date。
它的作用基本上是使用一个窗口,MAX其中包含组成日期列的 3 个字节的串联(这就是为什么我提到您的列必须是DATE,否则DATETIME将需要 8 个字节,您可以编辑查询来使用它)与组成价格列的字节(也假设为 5 个字节)。这就是这CAST(P.[date] AS BINARY(3)) + CAST(P.[price] AS BINARY(5))部分。
当您计算 和 时ORDER BY P.[date] ROWS UNBOUNDED PRECEDING,引擎基本上会使用滚动最大值,其中最重要的字节是您的日期。当日期更改时,最大结果将始终更新,但考虑到将任何值与NULL价格连接也会产生NULL(作为二进制),那么将MAX始终忽略该值并保留先前的非空值MAX(通过P.[date] ROWS UNBOUNDED PRECEDING)。
这是窗口化的二进制结果MAX(我添加了一条先前的记录,NULL因此您可以看到结果NULL为空价格值):
date price ff_price WindowedMax
2016-07-10 NULL NULL NULL
2016-07-11 0.79 0.79 0x9B3B0B050200014F
2016-07-12 NULL 0.79 0x9B3B0B050200014F
2016-07-13 NULL 0.79 0x9B3B0B050200014F
2016-07-14 0.69 0.69 0x9E3B0B0502000145
2016-07-15 NULL 0.69 0x9E3B0B0502000145
2016-07-21 0.88 0.88 0xA53B0B0502000158
2016-07-22 NULL 0.88 0xA53B0B0502000158
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1656 次 |
| 最近记录: |