Weighted Average

This subflow calculates the weighted average of given values, considering the date of each value. The more recent the date, the higher the value will be weighted in the average calculation.

Usage

  1. Prepare the input data structure and place it in the msg.payload.value.data property. The structure should follow this format:
{
  "attr_name1": [
    {"value": x, "date": y},
    {"value": z, "date": e}
  ],
  "attr_name2": [
    {"value": q, "date": w},
    ...
  ]
}

Each attribute (attr_name1, attr_name2, etc.) is associated with a list of dictionaries representing value entries.

Each value entry dictionary must contain two keys:

  • "value": Specifies the value of the attribute for a specific date.
  • "date": Specifies the date of the value entry in UNIX timestamp format.

Execute the subflow to calculate the weighted averages.

The subflow returns an object with keys corresponding to the attribute names specified in the input list, along with their respective weighted averages.

The output can be found in the msg.payload.value.data property. Advanced Options

To assign higher weight to older dates in the weighted average, set msg.payload.value.reverse to true.

[{"id":"6fd479bb119a914b","type":"subflow","name":"QuickSort","info":"<div>\n  <p>\n    This is the implementation of the Quick Sort algorithm, which can also perform a reverse sort if desired.\n    To choose reverse sort, put <code>msg.payload.value.reverse</code> to True, else put it False.\n  </p>\n  <p>\n    It takes as input a list with the following structure (put this in the <code>msg.payload.value.data</code>):\n    <code>\n      {\n        \"attr_name1\": [\n          {\"value\": x, \"date\": y},\n          {\"value\": z, \"date\": e}\n        ],\n        \"attr_name2\": [\n          {\"value\": q, \"date\": w},\n          ...\n        ]\n      }\n    </code>\n  </p>\n  <p>\n    In the input list, each attribute (<em>attr_name1</em>, <em>attr_name2</em>, etc.) is associated with a list of dictionaries.\n    Each dictionary represents a value entry and contains two keys that should remain as is:\n  </p>\n  <ul>\n    <li><strong>\"value\"</strong>: Specifies the value of the attribute for a specific date.</li>\n    <li><strong>\"date\"</strong>: Specifies the date of the value entry. The date should be in UNIX timestamp format.</li>\n  </ul>\n  <p>\n    The subflow returns the same structure as the input list, but with the lists of each attribute key sorted either normally or in reverse order, based on the chosen option. The output can be found in <code>msg.payload.value.data</code>.\n  </p>\n</div>\n","category":"","in":[{"x":140,"y":120,"wires":[{"id":"8a975444807b5c68"}]}],"out":[{"x":580,"y":120,"wires":[{"id":"6fef86d08511923a","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"8a975444807b5c68","type":"function","z":"6fd479bb119a914b","name":"Quick Sort","func":"function quickSort(arr, left, right) {\n    if (left < right) {\n        const pivotIndex = partition(arr, left, right);\n        quickSort(arr, left, pivotIndex - 1);\n        quickSort(arr, pivotIndex + 1, right);\n    }\n    return arr;\n}\n\nfunction partition(arr, left, right) {\n    // const pivot = new Date(arr[right].date);\n    const pivot = arr[right].date;\n    let i = left - 1;\n\n    for (let j = left; j < right; j++) {\n        // const currentDate = new Date(arr[j].date);\n        const currentDate = arr[j].date;\n        if (currentDate < pivot) {\n            i++;\n            swap(arr, i, j);\n        }\n    }\n\n    swap(arr, i + 1, right);\n    return i + 1;\n}\n\nfunction swap(arr, i, j) {\n    const temp = arr[i];\n    arr[i] = arr[j];\n    arr[j] = temp;\n}\n\nvar list = msg.payload.value.data;\nfor (let key in list) {\n    list[key] = quickSort(list[key], 0, list[key].length - 1);\n}\nmsg.payload.value.data = list;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":270,"y":120,"wires":[["6fef86d08511923a"]]},{"id":"6fef86d08511923a","type":"function","z":"6fd479bb119a914b","name":"Reverse Sort","func":"// Input: list - array of dictionaries [{ temperature: number, date: string }]\nif (!msg.payload.value.reverse) {\n    return msg;\n}\n\nvar list = msg.payload.value.data;\n// console.log(list);\nfor (let key in list) {\n    list[key] = list[key].reverse();\n}\nmsg.payload.value.data = list;\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":450,"y":120,"wires":[[]]},{"id":"da362e744a99a41b","type":"subflow","name":"Calculate Weighted Average","info":"<div>\n  <p>\n    This subflow calculates the weighted average of given values, considering the date of each value.\n    The more recent the date, the higher the value will be weighted in the average calculation.\n  </p>\n  <p>\n    It takes as input a list with the following structure (put this in the <code>msg.payload.value.data</code>):\n    <code>\n      {\n        \"attr_name1\": [\n          {\"value\": x, \"date\": y},\n          {\"value\": z, \"date\": e}\n        ],\n        \"attr_name2\": [\n          {\"value\": q, \"date\": w},\n          ...\n        ]\n      }\n    </code>\n  </p>\n  <p>\n    In the input list, each attribute (<em>attr_name1</em>, <em>attr_name2</em>, etc.) is associated with a list of dictionaries.\n    Each dictionary represents a value entry and contains two keys that should remain as is:\n  </p>\n  <ul>\n    <li><strong>\"value\"</strong>: Specifies the value of the attribute for a specific date.</li>\n    <li><strong>\"date\"</strong>: Specifies the date of the value entry. The date should be in UNIX timestamp format.</li>\n  </ul>\n  <p>\n    The subflow returns an object with keys corresponding to the attribute names specified in the input list, along with their respective weighted averages. The output can be found in <code>msg.payload.value.data</code>.\n  </p>\n  <p>\n    If you want the more old dates to have higher weight in the weighted average, set <code>msg.payload.value.reverse = True</code>.  \n  </p>\n</div>\n","category":"","in":[{"x":140,"y":180,"wires":[{"id":"d8e9daa2c8509009"}]}],"out":[{"x":780,"y":180,"wires":[{"id":"a305889cee5bf6fb","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"a305889cee5bf6fb","type":"function","z":"da362e744a99a41b","name":"Calculate Weighted Average","func":"// function conv_date(unixTime){\n//     // Create a new Date object by multiplying the Unix timestamp by 1000 to convert it to milliseconds\n//     const date = new Date(unixTime);\n\n//     // Extract the various components of the date and time\n//     const year = date.getFullYear();\n//     const month = date.getMonth() + 1; // Months are zero-based, so add 1\n//     const day = date.getDate();\n//     const hours = date.getHours();\n//     const minutes = date.getMinutes();\n//     const seconds = date.getSeconds();\n\n//     // Create a formatted date and time string\n//     return `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')} ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;\n\n// }\n\nfunction calc_weight_avg(list) {\n    // Calculate total weight and weighted sum\n    let totalWeight = 0;\n    let weightedSum = 0;\n\n    list.forEach((temperature, index) => {\n        const weight = index + 1;\n        // Used for debugging:\n        // console.log(conv_date(temperature.date) + \": \" + weight);\n        weightedSum += temperature.value * weight;\n        totalWeight += weight;\n    });\n\n    const weightedAverage = weightedSum / totalWeight;\n    return weightedAverage;\n}\n\nconst list = msg.payload.value.data;\nfor (let key in list) {\n    list[key] = calc_weight_avg(list[key]);\n}\n\nmsg.payload.value.data = list;\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":560,"y":180,"wires":[[]]},{"id":"d8e9daa2c8509009","type":"subflow:6fd479bb119a914b","z":"da362e744a99a41b","name":"","x":320,"y":180,"wires":[["a305889cee5bf6fb"]]}]

Flow Info

Created 2 years, 1 month ago
Rating: not yet rated

Owner

Actions

Rate:

Node Types

Core
  • function (x3)
Other
  • subflow (x2)
  • subflow:6fd479bb119a914b (x1)

Tags

  • weighted
  • average
  • quicksort
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option