使用Javascript和Mongodb重新采样时间序列数据

4 投票
1 回答
2493 浏览
提问于 2025-04-18 12:30

有一个时间序列的数据集,它的时间间隔不规律,我们需要把它转换成一个时间间隔规律的时间序列,可能需要用到插值和重采样的方法。

Python中的pandas.Dataframe.resample函数可以做到这一点。那么,JavaScript能做到同样的事情吗?这个时间序列的数据集存储在Mongodb里。

1 个回答

4

这其实是有可能的。要记住,Pandas是一个专门为这类任务设计的库,处理这类事情非常强大,而MongoDB则是一个数据库。不过,如果不考虑你可能需要插值的情况,下面的方法很可能能满足你的需求:

假设你在一个名为 devices 的MongoDB集合中存储了以下数据:

/* 0 */
{
    "_id" : ObjectId("543fc08ccf1e8c06c0288802"),
    "t" : ISODate("2014-10-20T14:56:44.097+02:00"),
    "a" : "192.168.0.16",
    "i" : 0,
    "o" : 32
}

/* 1 */
{
    "_id" : ObjectId("543fc08ccf1e8c06c0288803"),
    "t" : ISODate("2014-10-20T14:56:59.107+02:00"),
    "a" : "192.168.0.16",
    "i" : 14243,
    "o" : 8430
}

and so on...

这些数据大约每15秒采样一次,但也可能是不规则的。如果你想把这些数据重新采样到某一天的5分钟间隔,你可以这样做:

var low = ISODate("2014-10-23T00:00:00.000+02:00")
var high = ISODate("2014-10-24T00:00:00.000+02:00")
var interval = 5*60*1000;
db.devices.aggregate([
  {$match: {t:{$gte: low, $lt: high}, a:"192.168.0.16"}},
  {$group: {
     _id:{
       $subtract: ["$t", {
         $mod: [{
           $subtract: ["$t", low]
         }, interval]
       }]
     },
     total: {$sum: 1},
     incoming: {$sum: "$i"},
     outgoing: {$sum: "$o"},
    }
  },
  {
    $project: {
      total: true,
      incoming: true,
      outgoing: true,
      incoming_avg: {$divide: ["$incoming", "$total"]},
      outgoing_avg: {$divide: ["$outgoing", "$total"]},
    },
  },
  {$sort: {_id : 1}}
])

这样处理后,结果会像这样:

{
    "result" : [ 
        {
            "_id" : ISODate("2014-10-23T07:25:00.000+02:00"),
            "total" : 8,
            "incoming" : 11039108,
            "outgoing" : 404983,
            "incoming_avg" : 1379888.5,
            "outgoing_avg" : 50622.875
        }, 
        {
            "_id" : ISODate("2014-10-23T07:30:00.000+02:00"),
            "total" : 19,
            "incoming" : 187241,
            "outgoing" : 239912,
            "incoming_avg" : 9854.78947368421,
            "outgoing_avg" : 12626.94736842105
        }, 
        {
            "_id" : ISODate("2014-10-23T07:35:00.000+02:00"),
            "total" : 17,
            "incoming" : 22420099,
            "outgoing" : 1018766,
            "incoming_avg" : 1318829.352941176,
            "outgoing_avg" : 59927.41176470588
        },
        ...

如果你想忽略总的输入数据,只需在$project阶段省略那一行。incoming_average只是一个计算平均值的示例,假设你存储的数据类似于rrdtool所称的计量器(比如温度、CPU、传感器数据)。如果你只关心在那个时间段内的总和,也就是incoming和outgoing字段,那么可以完全省略$project阶段。这个阶段只是用来计算时间间隔的平均值。

你可以查看这个链接了解更多信息:Mongo聚合ISODate为45分钟块

撰写回答