即时插值大型数据集

9

大数据插值

我有一个庞大的数据集,约有50万条记录,表示给定一天内美元/英镑汇率的变化情况。

我有一个应用程序希望能够绘制这些数据或其中的一个子集。由于明显的原因,我不想在我的图表上绘制50万个点。

我需要一个较小的数据集(大约100个点),尽可能准确地表示给定的数据。有人知道任何有趣且效率高的方法可以实现这种数据吗?

谢谢,卡尔


1
你能澄清一下“代表”的含义吗?你是指仅在视觉上还是为了进行计算? - Carl
最终结果将是一个数据集,可以进行处理和绘图。 - Karl
1
听起来像是 R 的工作! - Joel
6个回答

4
有几种统计方法可以将大型数据集缩小为更小、更易于可视化的数据集。从您的问题中并不清楚您想要哪种摘要统计量。我假设您想看到汇率随时间变化的情况,但也许您对汇率何时超过某个特定值或其他我没有考虑的统计量感兴趣。
在这里,我们使用R中的lowess方法作为示例(取自scatter plot smoothing文档)。
> library(graphics)
# print out the first 10 rows of the cars dataset
> cars[1:10,]
   speed dist
1      4    2
2      4   10
3      7    4
4      7   22
5      8   16
6      9   10
7     10   18
8     10   26
9     10   34
10    11   17

# plot the original data
> plot(cars, main = "lowess(cars)")
# fit a loess-smoothed line to the points
> lines(lowess(cars), col = 2)
# plot a finger-grained loess-smoothed line to the points
> lines(lowess(cars, f=.2), col = 3)

参数f控制回归对数据的拟合程度。在使用时要考虑周全,确保准确地拟合数据而不过度拟合。您可以将汇率与时间绘制成图表,而不是速度和距离。
访问平滑结果也很简单。以下是如何操作:
> data = lowess( cars$speed, cars$dist )
> data
$x
 [1]  4  4  7  7  8  9 10 10 10 11 11 12 12 12 12 13 13 13 13 14 14 14 14 15 15 15 16 16 17 17 17 18 18 18 18 19 19
[38] 19 20 20 20 20 20 22 23 24 24 24 24 25

$y
 [1]  4.965459  4.965459 13.124495 13.124495 15.858633 18.579691 21.280313 21.280313 21.280313 24.129277 24.129277
[12] 27.119549 27.119549 27.119549 27.119549 30.027276 30.027276 30.027276 30.027276 32.962506 32.962506 32.962506
[23] 32.962506 36.757728 36.757728 36.757728 40.435075 40.435075 43.463492 43.463492 43.463492 46.885479 46.885479
[34] 46.885479 46.885479 50.793152 50.793152 50.793152 56.491224 56.491224 56.491224 56.491224 56.491224 67.585824
[45] 73.079695 78.643164 78.643164 78.643164 78.643164 84.328698

你得到的数据对象包含名为x和y的条目,它们对应于传递到lowess函数中的x和y值。在这种情况下,x和y表示速度和距离。

3

有一个想法是使用数据库管理系统(DBMS)来使用适当的查询压缩数据。可以通过对特定范围进行中位数计算等伪查询操作来实现:

SELECT truncate_to_hour(rate_ts), median(rate) FROM exchange_rates 
WHERE rate_ts >= start_ts AND rate_ts <= end_ts
GROUP BY truncate_to_hour(rate_ts)
ORDER BY truncate_to_hour(rate_ts)

其中truncate_to_hour是适合您的数据库管理系统的某些内容。或者使用类似的方法将时间分成唯一的块(例如四舍五入到最近的5分钟间隔),或者使用另一种适合于中位数替代的数学函数来聚合组。鉴于时间分段程序的复杂性以及您的数据库管理系统优化它的方式,可能更有效地在临时表上运行查询,并获得分段时间值。


1

类似 RRDTool 这样的工具可以自动完成你所需的操作 - tutorial 可以帮助你入门,而 drraw 则可以绘制数据图表。

我在工作中使用它来绘制错误图表,对于6个月时间段内的1分钟分辨率,我不需要,只需要最近几个小时的分辨率。之后,我会有几天的1小时分辨率,然后是几个月的1天分辨率。


1

如果你想要编写自己的程序,一个显而易见的解决方案是将记录集分成固定数量的点块,其值为平均值(平均数、中位数等选择一个)。这可能具有最快的优势,并显示整体趋势。

但它缺乏价格波动的戏剧性。更好的解决方案可能涉及查找拐点,然后使用滑动窗口在它们之间进行选择。这具有更好地显示当天实际事件的优点,但速度会较慢。


1

天真的方法就是计算每个像素对应时间间隔的平均值。

http://commons.wikimedia.org/wiki/File:Euro_exchange_rate_to_AUD.svg

这不显示波动。我建议在每个时间间隔内计算标准差,并将其绘制出来(实际上使每个像素高于一个单独的像素)。我找不到一个例子,但我知道Gnuplot可以做到这一点(但它不是用Java编写的)。


“真正的天真解决方案”就是简单地取每个第N个值。我预计在一个10万数据集中,例如每100个值取一个值仍然可以很好地展现测量值的历史,并且在性能方面没有其他方法可以与之匹敌。” - Tomislav Nakic-Alfirevic
真的。 看起来速度比像素精度更重要。 - Thorbjørn Ravn Andersen
这个答案看起来有点...熟悉。;] - CPerkins
毫不意外。看了你的答案,再看了我的。我们似乎想到了类似的东西。 - CPerkins

0

考虑创建枚举/迭代器包装器。我不熟悉Java,但它可能看起来类似于:

class MedianEnumeration implements Enumeration<Double>
{
    private Enumeration<Double> frameEnum;
    private int frameSize;

    MedianEnumeration(Enumeration<Double> e, int len) {
        frameEnum = e;
        frameSize = len;
    }

    public boolean hasMoreElements() {
        return frameEnum.hasMoreElements();
    }

    public Double nextElement() {
        Double sum = frameEnum.nextElement();

        int i;
        for(i=1; (i < frameSize) && (frameEnum.hasMoreElements()); ++i) {
            sum += (Double)frameEnum.nextElement();
        }

        return (sum / i);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接