db.collection.aggregate(
[
{
"$addFields": {
"indexes": {
"$range": [
0,
{
"$size": "$time_series"
}
]
},
"reversedSeries": {
"$reverseArray": "$time_series"
}
}
},
{
"$project": {
"derivatives": {
"$reverseArray": {
"$slice": [
{
"$map": {
"input": {
"$zip": {
"inputs": [
"$reversedSeries",
"$indexes"
]
}
},
"in": {
"$subtract": [
{
"$arrayElemAt": [
"$$this",
0
]
},
{
"$arrayElemAt": [
"$reversedSeries",
{
"$add": [
{
"$arrayElemAt": [
"$$this",
1
]
},
1
]
}
]
}
]
}
}
},
{
"$subtract": [
{
"$size": "$time_series"
},
1
]
}
]
}
},
"time_series": 1
}
}
]
)
ऐसा करने के लिए हम संस्करण 3.4+ में उपरोक्त पाइपलाइन का उपयोग कर सकते हैं। पाइपलाइन में, हम $addFields
पाइपलाइन चरण। दस्तावेज़ करने के लिए "time_series" के तत्वों के सूचकांक की सरणी जोड़ने के लिए ऑपरेटर, हमने समय श्रृंखला सरणी को भी उलट दिया और इसे क्रमशः $range
और $reverseArray
ऑपरेटर्स
हमने यहां ऐरे को उलट दिया है क्योंकि तत्व p
. पर स्थित है सरणी में हमेशा स्थिति पर तत्व से बड़ा होता है p+1
जिसका अर्थ है कि [p] - [p+1] <0
और हम $multiply
का इस्तेमाल नहीं करना चाहते
यहाँ। (संस्करण 3.2 के लिए पाइपलाइन देखें)
आगे हम $zipped
इंडेक्स एरे के साथ टाइम सीरीज़ डेटा और एक subtract
लागू किया। कोड>
$map
. का उपयोग करके परिणामी सरणी के लिए अभिव्यक्ति ऑपरेटर।
फिर हम $slice
शून्य/कोई नहीं
को छोड़ने का परिणाम सरणी से मूल्य और परिणाम को फिर से उलट दिया।
3.2 में हम $unwind
का इस्तेमाल कर सकते हैं
खोलने . के लिए ऑपरेटर हमारे सरणी और $ द्वारा उपसर्ग किए गए पारंपरिक "पथ" के बजाय दस्तावेज़ को ऑपरेंड के रूप में निर्दिष्ट करके सरणी में प्रत्येक तत्व की अनुक्रमणिका शामिल करें ।
पाइपलाइन में अगला, हमें $group
हमारे दस्तावेज़ और $push
का उपयोग करें
इस तरह दिखने वाले उप-दस्तावेजों की एक सरणी वापस करने के लिए संचायक ऑपरेटर:
{
"_id" : ObjectId("57c11ddbe860bd0b5df6bc64"),
"time_series" : [
{ "value" : 10, "index" : NumberLong(0) },
{ "value" : 20, "index" : NumberLong(1) },
{ "value" : 40, "index" : NumberLong(2) },
{ "value" : 70, "index" : NumberLong(3) },
{ "value" : 110, "index" : NumberLong(4) }
]
}
अंत में आता है $project
मंच। इस चरण में, हमें $mapकोड का उपयोग करने की आवश्यकता है। कोड>
ऑपरेटर $group
. में नई गणना की गई सरणी में प्रत्येक तत्व के लिए अभिव्यक्ति की एक श्रृंखला लागू करने के लिए मंच।
यहाँ क्या चल रहा है $map
. के अंदर (देखें $नक्शा
लूप के रूप में) में अभिव्यक्ति:
प्रत्येक उप-दस्तावेज़ के लिए, हम मान . निर्दिष्ट करते हैं $let
का इस्तेमाल करके वेरिएबल को फ़ील्ड करें
परिवर्तनीय ऑपरेटर। फिर हम इसे सरणी में अगले तत्व के "मान" फ़ील्ड के मान से घटाते हैं।
चूंकि सरणी में अगला तत्व वर्तमान इंडेक्स प्लस वन का तत्व है, इसलिए हमें केवल $arrayElemAt
ऑपरेटर और एक साधारण $add
वर्तमान तत्व की अनुक्रमणिका और 1
.
$subtract
व्यंजक एक ऋणात्मक मान लौटाता है, इसलिए हमें मान को -1
. से गुणा करना होगा $multiply
का इस्तेमाल करके
ऑपरेटर।
हमें $filter
की भी आवश्यकता है
परिणामी सरणी क्योंकि यह अंतिम तत्व है कोई नहीं
या शून्य
. इसका कारण यह है कि जब वर्तमान तत्व अंतिम तत्व होता है, $subtract
वापसी कोई नहीं
क्योंकि अगले तत्व का सूचकांक सरणी के आकार के बराबर है।
db.collection.aggregate([
{
"$unwind": {
"path": "$time_series",
"includeArrayIndex": "index"
}
},
{
"$group": {
"_id": "$_id",
"time_series": {
"$push": {
"value": "$time_series",
"index": "$index"
}
}
}
},
{
"$project": {
"time_series": {
"$filter": {
"input": {
"$map": {
"input": "$time_series",
"as": "el",
"in": {
"$multiply": [
{
"$subtract": [
"$$el.value",
{
"$let": {
"vars": {
"nextElement": {
"$arrayElemAt": [
"$time_series",
{
"$add": [
"$$el.index",
1
]
}
]
}
},
"in": "$$nextElement.value"
}
}
]
},
-1
]
}
}
},
"as": "item",
"cond": {
"$gte": [
"$$item",
0
]
}
}
}
}
}
])
एक अन्य विकल्प जो मुझे लगता है कि कम कुशल है map_reduce
विधि।
>>> import pymongo
>>> from bson.code import Code
>>> client = pymongo.MongoClient()
>>> db = client.test
>>> collection = db.collection
>>> mapper = Code("""
... function() {
... var derivatives = [];
... for (var index=1; index<this.time_series.length; index++) {
... derivatives.push(this.time_series[index] - this.time_series[index-1]);
... }
... emit(this._id, derivatives);
... }
... """)
>>> reducer = Code("""
... function(key, value) {}
... """)
>>> for res in collection.map_reduce(mapper, reducer, out={'inline': 1})['results']:
... print(res) # or do something with the document.
...
{'value': [10.0, 20.0, 30.0, 40.0], '_id': ObjectId('57c11ddbe860bd0b5df6bc64')}
आप सभी दस्तावेज़ पुनः प्राप्त कर सकते हैं और numpy.diff
. का उपयोग कर सकते हैं इस तरह व्युत्पन्न वापस करने के लिए:
import numpy as np
for document in collection.find({}, {'time_series': 1}):
result = np.diff(document['time_series'])