MongoDB で グループごと に データの平均/標準偏差/分散 を 集計する

0 件のコメント

今回は「MongoDB で グループごと に データの平均、標準偏差、分散 を 集計する 方法」についてまとめます。

MongoDB でグループ化に関する記事はほかにも以下のような記事がありますので参考にしていただければと思います。

前提データ

以下のデータを mongo コマンドで投入してある状態で各 item について集計を行っていきます。

1
2
3
4
5
6
7
8
9
10
11
12
> db.orders.insertMany([
  { datetime: ISODate("2017-12-15T12:00:00+09:00"), item: "pen", amount: 70 },
  { datetime: ISODate("2017-12-15T12:00:00+09:00"), item: "note", amount: 40 },
  { datetime: ISODate("2017-12-15T12:00:00+09:00"), item: "eraser", amount: 100 },
  { datetime: ISODate("2017-12-12T12:00:00+09:00"), item: "note", amount: 80 },
  { datetime: ISODate("2017-12-08T12:00:00+09:00"), item: "eraser", amount: 50 },
  { datetime: ISODate("2017-11-21T12:00:00+09:00"), item: "eraser", amount: 70 },
  { datetime: ISODate("2017-11-13T12:00:00+09:00"), item: "pen", amount: 20 },
  { datetime: ISODate("2017-11-02T12:00:00+09:00"), item: "pen", amount: 40 },
  { datetime: ISODate("2017-10-23T12:00:00+09:00"), item: "pen", amount: 30 },
  { datetime: ISODate("2017-10-18T12:00:00+09:00"), item: "pen", amount: 10 }
]);

グループごとに平均を集計(group avg)

平均の集計は $avg オペレーターを利用すると算出できます。 $avg オペレーターは引数を1つ(平均値を求めたいフィールド名)を指定するだけです。 単純なので早速コードを見てみましょう。

コード(index.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var MongoClient = require("mongodb").MongoClient;
 
MongoClient.connect(URL, (err, client) => {
  if (err) {
    client.close();
    return;
  }
 
  var db = client.db("sample");
 
  db.collection("orders").aggregate([
    {
      $group: {
        _id: "$item",
        avg: { $avg: "$amount" }
      }
    }
  ]).toArray().then((docs) => {
    console.log(docs);
  }).catch((err) => {
    console.log(err);
  }).then(() => {
    client.close();
  });
});

実行 & 結果

1
2
3
4
> node .\index.js
[ { _id: 'note', avg: 60 },
  { _id: 'eraser', avg: 73.33333333333333 },
  { _id: 'pen', avg: 34 } ]

グループごとに標準偏差を集計(group stddev)

標準偏差には「母標準偏差」と「標本標準偏差」の2種類が存在します。 「母標準偏差」は「調査したデータと推定したいデータがすべて一致する場合(例えば、クラス全員の身長のばらつきを調べるような全量調査可能なケース)」で、 「標本標準偏差」は「調査対象データが推定対象データの一部である場合(例えば、日本中の身長のばらつきを調べるような部分的なデータしか集計できないケース」の値になります。

「母標準偏差」であれば $stdDevPop を使い、「標本標準偏差」であれば $stdDevSamp を使います。 どちらのオペレーターも集計対象としたいフィールド名を引数に1つとるものになります。

今回は「母標準偏差」をサンプルコードとして準備しました。 「標本標準偏差」で求めたい場合は $stdDevPop を $stdDevSamp へ置き換えてください。

コード(index.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var MongoClient = require("mongodb").MongoClient;
 
MongoClient.connect(URL, (err, client) => {
  if (err) {
    client.close();
    return;
  }
 
  var db = client.db("sample");
 
  db.collection("orders").aggregate([
    {
      $group: {
        _id: "$item",
        stddev: { $stdDevPop: "$amount" }
      }
    }
  ]).toArray().then((docs) => {
    console.log(docs);
  }).catch((err) => {
    console.log(err);
  }).then(() => {
    client.close();
  });
});

実行 & 結果

1
2
3
4
> node .\index.js
[ { _id: 'note', stddev: 20 },
  { _id: 'eraser', stddev: 20.548046676563256 },
  { _id: 'pen', stddev: 20.591260281974 } ]

グループごとに分散を集計(group var)

標準偏差があればあまり分散を使うこともない…という前提なのか、直接分散を求めるオペレーターはないので標準偏差から元に戻すことになります。 いったん標準偏差を求めて2乗することで分散を求めます。

コード(index.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var MongoClient = require("mongodb").MongoClient;
 
MongoClient.connect(URL, (err, client) => {
  if (err) {
    client.close();
    return;
  }
 
  var db = client.db("sample");
 
  db.collection("orders").aggregate([
    {
      $group: {
        _id: "$item",
        stddev: { $stdDevPop: "$amount" }
      }
    },
    {
      $project: {
        var: { $pow: ["$stddev", 2] }
      }
    }
  ]).toArray().then((docs) => {
    console.log(docs);
  }).catch((err) => {
    console.log(err);
  }).then(() => {
    client.close();
  });
});

実行 & 結果

1
2
3
4
> node .\index.js
[ { _id: 'note', var: 400 },
  { _id: 'eraser', var: 422.2222222222223 },
  { _id: 'pen', var: 424.00000000000006 } ]

今回は「MongoDB で グループごと に データの平均/標準偏差/分散 を 集計する 方法」についてまとめました。 ポイントは以下の通りです。

  • 平均は { $avg: <key> }
  • 標準偏差は { $stdDevPop: <key> } または { $stdDevSamp: <key> }
  • 分散は標準偏差を求めて2乗

参考になったでしょうか? 本記事がお役に立っていると嬉しいです!!

最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!