Average of every hour in a array - javascript

I have a array which updates every minute. When i want to show it over a day, I want to have the average of every hour that day.
The most recent minute is add the end of the array.
//get the last elements from the array
var hours= (this.today.getHours() + 1) * 60
var data = Array.from(this.temps.data)
let lastData = data.slice(Math.max(data.length - hours))
let newData: any
// calculate the average of every hour
for (let i = 0; i < minutes; i++) {
var cut = i * 60
for (let i = cut; i < (cut + 60); i++) {
newData = newData + lastData[i];
let test = newData/60
console.log(test);
}
}
I can't figure out how I make an array from every last 60 elements.
My goal is to get an array like
avgHour[20,22,30,27,]
The array I have is updated every minute. So I need the average of every 60 elements to get a hour.
array looks like this
data[25,33,22,33]
It is every minute from a week so really long.
This Worked For me
var arrays = [], size = 60;
while (arr.length > 0){
arrays.push(arr.splice(0, size));
}
for (let i = 0; i < (arrays.length - 1); i++) {
var sum = 0
for (let b = 0; b < 60; b++) {
sum += arrays[i][b]
}
let avg = sum/60
arr2.push(avg)
}
this just splits the array every 60 elements. Now I can calculate the average for every 60.
duplicate of How to split a long array into smaller arrays, with JavaScript
Thanks for the help!

I am a big fan of the functional programming library Ramda. (Disclaimer: I'm one of its authors.) I tend to think in terms of simple, reusable functions.
When I think of how to solve this problem, I think of it through a Ramda viewpoint. And I would probably solve this problem like this:
const avgHour = pipe(
splitEvery(60),
map(mean),
)
// some random data
const data = range(0, 7 * 24 * 60).map(_ => Math.floor(Math.random() * 20 + 10))
console.log(avgHour(data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>const {pipe, splitEvery, map, mean, range} = R</script>
I think that is fairly readable, at least once you understand that pipe creates a pipeline of functions, each handing its result to the next one.
Now, there is often not a reason to include a large library like Ramda to solve a fairly simple problem. But all the functions used in that version are easily reusable. So it might make sense to try to create your own versions of these functions and keep them available to the rest of your application. In fact, that's how libraries like Ramda actually get built.
So here is a version that has simple implementations of those functions, ones you might place in a utility library:
const pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x)
const splitEvery = (n) => (xs) => {
let i = 0, a = []
while (i < xs.length) {a.push(xs.slice(i, i + n)); i += n}
return a
}
const map = (fn) => (xs) => xs.map(x => fn(x))
const sum = (xs) => xs.reduce((a, b) => a + b, 0)
const mean = (xs) => sum(xs) / (xs.length || 1)
const avgHour = pipe(
splitEvery(60),
map(mean)
)
const range = (lo, hi) => [...Array(hi - lo)].map((_, i) => lo + i)
// some random data
const data = range(0, 7 * 24 * 60).map(_ => Math.floor(Math.random() * 20 + 10))
console.log(avgHour(data))

You can reduce the data and group by hour, then simply map to get each hour's average. I'm using moment to parse the dates below, you can do that with whatever lib/js you prefer...
const arr = Array.from({length: 100}, () => ({time: moment().subtract(Math.floor(Math.random() * 10), 'hours'), value: Math.floor(Math.random() * 100)}));
const grouped = [...arr.reduce((a, b) => {
let o = a.get(b.time.get('hour')) || {value: 0, qty: 0};
a.set(b.time.get('hour'), {value: o.value + b.value, qty: o.qty + 1});
return a;
}, new Map)].map(([k, v]) => ({
[k]: v.value / v.qty
}));
console.log(grouped)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment-with-locales.min.js"></script>

By grouping and then reducing you can do this like following.
function groupBy(list, keyGetter) {
const map = {};
list.forEach((item) => {
const key = keyGetter(item);
if (!map[key]) {
map[key] = [item];
} else {
map[key].push(item);
}
});
return map;
}
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
const now = (new Date()).getTime();
const stepSize = 60000*1;
const withTime = data.reverse().map((x, i) => { return { time: new Date(now - stepSize * i), temp: x } });
const grouped = groupBy(withTime, x => new Date(x.time.getFullYear(), x.time.getMonth(), x.time.getDate(), x.time.getHours()).valueOf());
const avg = Object.entries(grouped).map((x) => {
return {
time: new Date(Number(x[0])),
temp: x[1].map(y => y.temp).reduce((acc, val) => acc + val) * (1.0 / x[1].length)
}
});
console.log(avg);

To measure the average I needed to split the array every 60 elements.
This is the solution I found
//Calculate the average of every 60 elements to get the average of an hour
var arr2: number[] = []
var arr: number[] = []
arr = Array.from(this.temps.data)
var arrays = [], size = 60;
while (arr.length > 0){
arrays.push(arr.splice(0, size));
}
for (let i = 0; i < (arrays.length - 1); i++) {
var sum = 0
for (let b = 0; b < 60; b++) {
sum += arrays[i][b]
}
let avg = sum/60
arr2.push(avg)
}
After all I think its stupid to get the last elements of the array, Because this is a better solution. But thanks for the help!

Related

Is there a Javascript function to calculate the median of a Set [duplicate]

I've been trying to calculate median but still I've got some mathematical issues I guess as I couldn't get the correct median value and couldn't figure out why. Here's the code;
class StatsCollector {
constructor() {
this.inputNumber = 0;
this.average = 0;
this.timeout = 19000;
this.frequencies = new Map();
for (let i of Array(this.timeout).keys()) {
this.frequencies.set(i, 0);
}
}
pushValue(responseTimeMs) {
let req = responseTimeMs;
if (req > this.timeout) {
req = this.timeout;
}
this.average = (this.average * this.inputNumber + req) / (this.inputNumber + 1);
console.log(responseTimeMs / 1000)
let groupIndex = Math.floor(responseTimeMs / 1000);
this.frequencies.set(groupIndex, this.frequencies.get(groupIndex) + 1);
this.inputNumber += 1;
}
getMedian() {
let medianElement = 0;
if (this.inputNumber <= 0) {
return 0;
}
if (this.inputNumber == 1) {
return this.average
}
if (this.inputNumber == 2) {
return this.average
}
if (this.inputNumber > 2) {
medianElement = this.inputNumber / 2;
}
let minCumulativeFreq = 0;
let maxCumulativeFreq = 0;
let cumulativeFreq = 0;
let freqGroup = 0;
for (let i of Array(20).keys()) {
if (medianElement <= cumulativeFreq + this.frequencies.get(i)) {
minCumulativeFreq = cumulativeFreq;
maxCumulativeFreq = cumulativeFreq + this.frequencies.get(i);
freqGroup = i;
break;
}
cumulativeFreq += this.frequencies.get(i);
}
return (((medianElement - minCumulativeFreq) / (maxCumulativeFreq - minCumulativeFreq)) + (freqGroup)) * 1000;
}
getAverage() {
return this.average;
}
}
Here's the snapshot of the results when I enter the values of
342,654,987,1093,2234,6243,7087,20123
The correct result should be;
Median: 1663.5
Change your median method to this:
function median(values){
if(values.length ===0) throw new Error("No inputs");
values.sort(function(a,b){
return a-b;
});
var half = Math.floor(values.length / 2);
if (values.length % 2)
return values[half];
return (values[half - 1] + values[half]) / 2.0;
}
fiddle
Here's another solution:
function median(numbers) {
const sorted = Array.from(numbers).sort((a, b) => a - b);
const middle = Math.floor(sorted.length / 2);
if (sorted.length % 2 === 0) {
return (sorted[middle - 1] + sorted[middle]) / 2;
}
return sorted[middle];
}
console.log(median([4, 5, 7, 1, 33]));
The solutions above - sort then find middle - are fine, but slow on large data sets. Sorting the data first has a complexity of n x log(n).
There is a faster median algorithm, which consists in segregating the array in two according to a pivot, then looking for the median in the larger set. Here is some javascript code, but here is a more detailed explanation
// Trying some array
alert(quickselect_median([7,3,5])); // 2300,5,4,0,123,2,76,768,28]));
function quickselect_median(arr) {
const L = arr.length, halfL = L/2;
if (L % 2 == 1)
return quickselect(arr, halfL);
else
return 0.5 * (quickselect(arr, halfL - 1) + quickselect(arr, halfL));
}
function quickselect(arr, k) {
// Select the kth element in arr
// arr: List of numerics
// k: Index
// return: The kth element (in numerical order) of arr
if (arr.length == 1)
return arr[0];
else {
const pivot = arr[0];
const lows = arr.filter((e)=>(e<pivot));
const highs = arr.filter((e)=>(e>pivot));
const pivots = arr.filter((e)=>(e==pivot));
if (k < lows.length) // the pivot is too high
return quickselect(lows, k);
else if (k < lows.length + pivots.length)// We got lucky and guessed the median
return pivot;
else // the pivot is too low
return quickselect(highs, k - lows.length - pivots.length);
}
}
Astute readers will notice a few things:
I simply transliterated Russel Cohen's Python solution into JS,
so all kudos to him.
There are several small optimisations worth
doing, but there's parallelisation worth doing, and the code as is
is easier to change in either a quicker single-threaded, or quicker
multi-threaded, version.
This is the average linear time
algorithm, there is more efficient a deterministic linear time version, see Russel's
post for details, including performance data.
ADDITION 19 Sept. 2019:
One comment asks whether this is worth doing in javascript. I ran the code in JSPerf and it gives interesting results.
if the array has an odd number of elements (one figure to find), sorting is 20% slower that this "fast median" proposition.
if there is an even number of elements, the "fast" algorithm is 40% slower, because it filters through the data twice, to find elements number k and k+1 to average. It is possible to write a version of fast median that doesn't do this.
The test used rather small arrays (29 elements in the jsperf test). The effect appears to be more pronounced as arrays get larger. A more general point to make is: it shows these kinds of optimisations are worth doing in Javascript. An awful lot of computation is done in JS, including with large amounts of data (think of dashboards, spreadsheets, data visualisations), and in systems with limited resources (think of mobile and embedded computing).
var arr = {
max: function(array) {
return Math.max.apply(null, array);
},
min: function(array) {
return Math.min.apply(null, array);
},
range: function(array) {
return arr.max(array) - arr.min(array);
},
midrange: function(array) {
return arr.range(array) / 2;
},
sum: function(array) {
var num = 0;
for (var i = 0, l = array.length; i < l; i++) num += array[i];
return num;
},
mean: function(array) {
return arr.sum(array) / array.length;
},
median: function(array) {
array.sort(function(a, b) {
return a - b;
});
var mid = array.length / 2;
return mid % 1 ? array[mid - 0.5] : (array[mid - 1] + array[mid]) / 2;
},
modes: function(array) {
if (!array.length) return [];
var modeMap = {},
maxCount = 1,
modes = [array[0]];
array.forEach(function(val) {
if (!modeMap[val]) modeMap[val] = 1;
else modeMap[val]++;
if (modeMap[val] > maxCount) {
modes = [val];
maxCount = modeMap[val];
}
else if (modeMap[val] === maxCount) {
modes.push(val);
maxCount = modeMap[val];
}
});
return modes;
},
variance: function(array) {
var mean = arr.mean(array);
return arr.mean(array.map(function(num) {
return Math.pow(num - mean, 2);
}));
},
standardDeviation: function(array) {
return Math.sqrt(arr.variance(array));
},
meanAbsoluteDeviation: function(array) {
var mean = arr.mean(array);
return arr.mean(array.map(function(num) {
return Math.abs(num - mean);
}));
},
zScores: function(array) {
var mean = arr.mean(array);
var standardDeviation = arr.standardDeviation(array);
return array.map(function(num) {
return (num - mean) / standardDeviation;
});
}
};
2022 TypeScript Approach
const median = (arr: number[]): number | undefined => {
if (!arr.length) return undefined;
const s = [...arr].sort((a, b) => a - b);
const mid = Math.floor(s.length / 2);
return s.length % 2 === 0 ? ((s[mid - 1] + s[mid]) / 2) : s[mid];
};
Notes:
The type in the function signature (number[]) ensures only an array of numbers can be passed to the function. It could possibly be empty though.
if (!arr.length) return undefined; checks for the possible empty array, which would not have a median.
[...arr] creates a copy of the passed-in array to ensure we don't overwrite the original.
.sort((a, b) => a - b) sorts the array of numbers in ascending order.
Math.floor(s.length / 2) finds the index of the middle element if the array has odd length, or the element just to the right of the middle if the array has even length.
s.length % 2 === 0 determines whether the array has an even length.
(s[mid - 1] + s[mid]) / 2 averages the two middle items of the array if the array's length is even.
s[mid] is the middle item of an odd-length array.
TypeScript Answer 2020:
// Calculate Median
const calculateMedian = (array: Array<number>) => {
// Check If Data Exists
if (array.length >= 1) {
// Sort Array
array = array.sort((a: number, b: number) => {
return a - b;
});
// Array Length: Even
if (array.length % 2 === 0) {
// Average Of Two Middle Numbers
return (array[(array.length / 2) - 1] + array[array.length / 2]) / 2;
}
// Array Length: Odd
else {
// Middle Number
return array[(array.length - 1) / 2];
}
}
else {
// Error
console.error('Error: Empty Array (calculateMedian)');
}
};
const median = (arr) => {
return arr.slice().sort((a, b) => a - b)[Math.floor(arr.length / 2)];
};
Short and sweet.
Array.prototype.median = function () {
return this.slice().sort((a, b) => a - b)[Math.floor(this.length / 2)];
};
Usage
[4, 5, 7, 1, 33].median()
Works with strings as well
["a","a","b","b","c","d","e"].median()
For better performance in terms of time complexity, use MaxHeap - MinHeap to find the median of stream of array.
Simpler & more efficient
const median = dataSet => {
if (dataSet.length === 1) return dataSet[0]
const sorted = ([ ...dataSet ]).sort()
const ceil = Math.ceil(sorted.length / 2)
const floor = Math.floor(sorted.length / 2)
if (ceil === floor) return sorted[floor]
return ((sorted[ceil] + sorted[floor]) / 2)
}
Simple solution:
function calcMedian(array) {
const {
length
} = array;
if (length < 1)
return 0;
//sort array asc
array.sort((a, b) => a - b);
if (length % 2) {
//length of array is odd
return array[(length + 1) / 2 - 1];
} else {
//length of array is even
return 0.5 * [(array[length / 2 - 1] + array[length / 2])];
}
}
console.log(2, calcMedian([1, 2, 2, 5, 6]));
console.log(3.5, calcMedian([1, 2, 2, 5, 6, 7]));
console.log(9, calcMedian([13, 9, 8, 15, 7]));
console.log(3.5, calcMedian([1, 4, 6, 3]));
console.log(5, calcMedian([5, 1, 11, 2, 8]));
Simpler, more efficient, and easy to read
cloned the data to avoid alterations to the original data.
sort the list of values.
get the middle point.
get the median from the list.
return the median.
function getMedian(data) {
const values = [...data];
const v = values.sort( (a, b) => a - b);
const mid = Math.floor( v.length / 2);
const median = (v.length % 2 !== 0) ? v[mid] : (v[mid - 1] + v[mid]) / 2;
return median;
}
const medianArr = (x) => {
let sortedx = x.sort((a,b)=> a-b);
let halfIndex = Math.floor(sortedx.length/2);
return (sortedx.length%2) ? (sortedx[Math.floor(sortedx.length/2)]) : ((sortedx[halfIndex-1]+sortedx[halfIndex])/2)
}
console.log(medianArr([1,2,3,4,5]));
console.log(medianArr([1,2,3,4,5,6]));
function Median(arr){
let len = arr.length;
arr = arr.sort();
let result = 0;
let mid = Math.floor(len/2);
if(len % 2 !== 0){
result += arr[mid];
}
if(len % 2 === 0){
result += (arr[mid] + arr[mid+1])/2
}
return result;
}
console.log(`The median is ${Median([0,1,2,3,4,5,6])}`)
function median(arr) {
let n = arr.length;
let med = Math.floor(n/2);
if(n % 2 != 0){
return arr[med];
} else{
return (arr[med -1] + arr[med])/ 2.0
}
}
console.log(median[1,2,3,4,5,6]);
The arr.sort() method sorts the elements of an array in place and returns the array. By default, it sorts the elements alphabetically, so if the array contains numbers, they will not be sorted in numerical order.
On the other hand, the arr.sort((a, b) => a - b) method uses a callback function to specify how the array should be sorted. The callback function compares the two elements a and b and returns a negative number if a should be sorted before b, a positive number if b should be sorted before a, and zero if the elements are equal. In this case, the callback function subtracts b from a, which results in a sorting order that is numerical in ascending order.
So, if you want to sort an array of numbers in ascending order, you should use arr.sort((a, b) => a - b), whereas if you want to sort an array of strings alphabetically, you can use arr.sort():
function median(numbers) {
const sorted = Array.from(numbers).sort((a, b) => a - b);
const middle = Math.floor(sorted.length / 2);
if (sorted.length % 2 === 0) {
return (sorted[middle - 1] + sorted[middle]) / 2;
}
return sorted[middle];
}
function findMedian(arr) {
arr.sort((a, b) => a - b)
let i = Math.floor(arr.length / 2)
return arr[i]
}
let result = findMedian([0, 1, 2, 4, 6, 5, 3])
console.log(result)

the most performant way finding an item in array within a range of indexes

I'm looking for something like the built-in Array.prototype.find(), but I want to be able to search starting from a given index, without creating a new shallow copy of range of items from this array.
possibilities:
using Array.prototype.find with no starting index.
using Array.prototype.slice() and then .find. something like arr.slice(startIndedx).find(...). creating shallow copy.
writing my own find implementation using for loop that start looking from given index.
using lodash.find(). but I care about bundle size and lodash is quite heavy. I actually prefer avoiding any kind of third-party packages.
here are some performance test results :
const SIZE = 1000000
const START_I = 800000
const ItemVal = 900000
...
find: average time: 12.1ms
findSlice: average time: 2.48ms
findLodash: average time: 0.26ms
myFind: average time: 0.26ms
surprisingly enough its seems that that native .find performed worse even with starting index 0 :
const SIZE = 1000000
const START_I = 0
const ItemVal = 900000
...
find: average time: 12.61ms
findSlice: average time: 17.51ms
findLodash: average time: 1.93ms
myFind: average time: 2.17ms
for array size 1000000 , starting index of 0 and the correct position is 900000, Array.prototype.find() preformed 12.61ms vs 2.17ms of the simple for loop search(!). am I missing something?
the test code is:
const {performance} = require('perf_hooks');
const _ = require('lodash')
const SIZE = 1000000
const START_I = 0
const ItemVal = 900000
let arr = Array(SIZE).fill(0)
arr = arr.map((a, i) => i)
const myFind = (arr, func, startI) => {
for (let i = startI; i < arr.length; i++) {
if (func(arr[i])) return arr[i]
}
return -1
}
const functions = {
find: () => arr.find(a => a === ItemVal), // looking at all array - no starting index
findSlice: () => arr.slice(START_I).find(a => a === ItemVal),
findLodash: () => _.find(arr, a => a === ItemVal, START_I),
myFind: () => myFind(arr, a => a === ItemVal, START_I),
}
const repeat = 100
const test_find = () => {
for (let [name, func] of Object.entries(functions)) {
let totalTime = 0
for (let i = 0; i < repeat; i++) {
let t_current = performance.now()
func()
totalTime += performance.now() - t_current
}
console.log(`${name}: average time: ${Math.round(totalTime / repeat * 100) / 100}ms`)
}
}
test_find()
what is the best way to find an item in an array stating looking from an index? and also, how does Array.prototype.find perform worse than my own simple for loop implementation of find?

How to populate an array with integers

Please, how do you populate an array say ‘num’ with numbers not in a second array say ‘fig’? I’m trying to use a loop to have the values of the already populated array ‘fig’ compared to ‘num’ which is to be populated with integers not found in ‘fig’. I’m a bit confused.
If you need to do an array with n numbers you can use this two ways.
const arrayLength = 100;
const numberArray = [...new Array(arrayLength).keys()]
const anotherWay = new Array(arrayLength).fill().map((_, idx) => idx + 1);
console.log(numberArray, anotherWay)
so to do this we have to do a few things:
1) define an existing array with numbers to avoid
2) define length on new array
3) generate a random number and make it an integer
4) check to see if we need to avoid
5) if it's a new value add it to the second array
var first=[55,45,35,1,2,3,4,5];
var second = [];
var i = 7;
var x;
while (i != 0){
x = ~~(Math.random()*100);
var check = false;
for(let j=0; j<first.length;j++){
if(x == first[j]){
check = true;
}
}
if(!check){
second.push(x);
i--;
}
}
console.log(second);
const fig = [-21, 0, 3, 6, 7, 42]
const min = Math.min(...fig) // or fig[0] if the the array is already sorted
const max = Math.max(...fig) // or fig[fig.length - 1]
const num = Array.from({ length: max - min }, (_, i) => i + min)
.filter(el => !fig.includes(el))
or, saving one loop
const num = Array.from({ length: max - min }).reduce((acc, _, i) => {
const curr = i + min
if (!fig.includes(curr)) {
return acc.concat(curr)
}
return acc
}, [])
This is assuming your range is from the smallest number in fig to the largest in fig.

More efficient way to calculate the average of a RGB color block in Javascript

I have an array of object with each holding rgb values and I want to get the average of channel.
[{ r: 234, g: 250, b: 0 }, { r: 234, g: 250, b: 0 }, { r: 234, g: 250, b: 0 }]
The straight forward method is to map through the array, get the sum of each of the r, g and b values, then divide each by the length of the array.
const arrLength = colorBlock.length
let redArr = colorBlock.map(obj => obj.r)
let greenArr = colorBlock.map(obj => obj.g)
let blueArr = colorBlock.map(obj => obj.b)
const add = (total, num) => total + num;
const totalR = redArr.reduce(add, 0);
const totalG = greenArr.reduce(add, 0);
const totalB = blueArr.reduce(add, 0);
const averageR = parseInt(totalR / arrLength)
const averageG = parseInt(totalG / arrLength)
const averageB = parseInt(totalB / arrLength)
My problem with this is that it's very slow when I have a big color block, a 900 x 900 block took about 5 seconds. Is there a more efficient way to do this?
EDIT: Sorry guy I make a mistake, the causes for my slow down actually came from the function that create the color block, not the average calculation. The calculation only took a few hundred millisecond.
Drop the separation of channels. Traversing one existing array once is likely more efficient than creating and filling 3 new arrays (which itself means traversing the original array 3 times), and then traversing all of them again.
let totals=colorBlock.reduce(
(totals,current)=>{
totals[0]+=current.r;
totals[1]+=current.g;
totals[2]+=current.b;
return totals;
},[0,0,0]);
let averageR=totals[0]/totals.length;
let averageG=totals[1]/totals.length;
let averageB=totals[2]/totals.length;
Your approach has the optimal time complexity. You could gain a factor of speed by avoiding callback functions, and relying on the plain old for loop (not the in or of variant, but the plain one):
const arrLength = colorBlock.length;
let totalR = 0, totalG = 0, totalB = 0;
for (let i = 0; i < arrLength; i++) {
let rgb = colorBlock[i];
totalR += rgb.r;
totalG += rgb.g;
totalB += rgb.b;
}
const averageR = Math.floor(totalR / arrLength);
const averageG = Math.floor(totalG / arrLength);
const averageB = Math.floor(totalB / arrLength);
You may at most halve the time tp process a 900x900 input with this, but that's about it.
To really improve more, you will need to rely on some heuristic that says that most of the time neighboring pixels will have about the same color code. And so you would then skip pixels. That will give you an estimated average, but that might be good enough for your purposes.
Remark: don't use parseInt when the argument is numeric. This will unnecessarily convert the argument to string, only to convert it back to number. Instead use Math.floor.
Use Array.reduce() on the entire object all at once, then Array.map() to calculate the averages:
const obj = [{ r: 200, g: 161, b: 1 }, { r: 50, g: 0, b: 3 }, { r: 50, g: 0, b: 5 }]
const res = obj.reduce((acc,cur) => {
acc[0] += cur.r
acc[1] += cur.g
acc[2] += cur.b
return acc
},[0,0,0]).map(cur => Math.round(cur / obj.length))
console.log(res)
Using a simple for loop instead of map and reduce can save quite a bit of time.
//Generate random colors
function genColor() {
return Math.floor(Math.random() * 255);
}
const SIZE = 500000;
const colorBlock = new Array(SIZE);
for(let i = 0; i < SIZE; i++) {
colorBlock[i] = {r:genColor(), g:genColor(), b:genColor()};
}
const arrLength = colorBlock.length;
var startTime0 = performance.now();
let redArr0 = colorBlock.map(obj => obj.r)
let greenArr0 = colorBlock.map(obj => obj.g)
let blueArr0 = colorBlock.map(obj => obj.b)
const add = (total, num) => total + num;
const totalR0 = redArr0.reduce(add, 0);
const totalG0 = greenArr0.reduce(add, 0);
const totalB0 = blueArr0.reduce(add, 0);
const averageR0 = Math.floor(totalR0 / arrLength)
const averageG0 = Math.floor(totalG0 / arrLength)
const averageB0 = Math.floor(totalB0 / arrLength)
var endTime0 = performance.now();
var totalR1 = 0;
var totalG1 = 0;
var totalB1 = 0;
for(let i = 0; i < SIZE; i++) {
totalR1 += colorBlock[i].r;
totalG1 += colorBlock[i].g;
totalB1 += colorBlock[i].b;
}
const averageR1 = Math.floor(totalR1 / arrLength)
const averageG1 = Math.floor(totalG1 / arrLength)
const averageB1 = Math.floor(totalB1 / arrLength)
var endTime1 = performance.now();
console.log( averageR0, averageG0, averageB0)
console.log( averageR1, averageG1, averageB1)
console.log("Reduce", endTime0 - startTime0);
console.log("for loop", endTime1 - endTime0);

how to filter a set of data by variance in typescript?

Let's say I have a set of data like this with a row for each minute in the last 4 hours:
[
{ X:1000, Y:2000, Z:3000, DateTime: 12/15/2018 12:00 },
{ X:998, Y:2011, Z:3020, DateTime: 12/15/2018 12:01 }
]
I need an array of property names whose values are within a 20% variance for all rows. So if Y and Z above meet this criteria but X does not then the output should look like this:
[Y, Z]
What typescript code could I use to do this?
I don't know exactly what "variance" or "variance percentage" mean in your question. I just used this formula to calculate variance: https://www.wikihow.com/Calculate-Variance
For the variance percentage, I simply divided the variance by the mean value and expressed it in percentage.
Feel free to replace my calculateVariancePercentage with a more correct implementation.
const ACCEPTABLE_VARIANCE_THRESHOLD = 20;
const dataset = [
{ X:1000, Y:2000, Z:3000, DateTime: '12/15/2018 12:00' },
{ X:998, Y:2011, Z:3020, DateTime: '12/15/2018 12:01' }
];
const calculateVariancePercentage = (data) => {
const meanValue = data.reduce((sum, element) => sum + element, 0) / data.length;
const sumOfDeviations = data.reduce((sod, element) => Math.pow(element - meanValue, 2), 0);
const variance = sumOfDeviations / (data.length - 1);
return variance / meanValue * 100;
}
const variables = Object.keys(dataset[0]).filter(key => key !== 'DateTime');
const result = variables.filter(variable => {
const varData = dataset.map(row => row[variable]);
const varianceInPercentage = calculateVariancePercentage(varData);
console.log(varianceInPercentage);
return calculateVariancePercentage(varData) <= ACCEPTABLE_VARIANCE_THRESHOLD;
});
console.log(result);

Categories