0
votes

I have a question about using ArrayFormula again. I have a list of 2 columns (datetime and currency). I need to find the average of the currency-column for the last 50 rows. I can't use formulas in every row because the length of the array can vary.

I already tried with a query (knowing it wouldn't work with ArrayFormula):

=ArrayFormula(query(U2:V; "select AVG(V) where (U > date '"&TEXT(WORKDAY($U139:U;-50); "YYYY-MM-DD")&"' AND U < date '"&TEXT($U139:U; "YYYY-MM-DD")&"') label AVG(V) ''"))

My next step was to trick it with indirect- adressing but this also doesn't work:

=ArrayFormula(IF($U2:$U>=$C$32;AVERAGE(INDIRECT("$V"&ROW()):INDIRECT("$V"&ROW()-50));""))

Here is an example sheet with both formulas: Avarage 50 example

Any ideas how to solve this issues?

2
What about AVERAGEIFS()? - Harun24HR
this works for 1 row. I need this in every row for the 50 predecessor rows without copying the formula... - Me.MyBase
There is not a good way to do this for more than about 2500 rows. I can show you the answer for that many if you're interested, but if you'll have longer time series than that, you may not be interested? - MattKing
Although my solution is not that elegant listing all 50 pairs of ranges, it will work as a single cell ARRAYFORMULA. Where the start date is 24/06/1998 17:30:00, it will average 50 days rolling, working on 5790 rows of data. - Aresvik

2 Answers

1
votes

MMULT()'s can be used to create conditional averages or sums like this, but they are limited to datsets under 2500 or so rows as they will virtually create a matrix that is N rows long, by N columns wide, where N is the length of your dataset.

N^2 has to be less than about 5 million as that's the "cell limit" in google sheets.

You'll find this formula in cell F2 on a new tab called MK.Help:

=ARRAYFORMULA(IF((E2:E="")+(ROW(D2:D)<50+1);;MMULT((ROW(D2:D)<=TRANSPOSE(ROW(D2:D)+50))*(ROW(D2:D)>=TRANSPOSE(ROW(D2:D)));N(E2:E))/50))
1
votes

Since you say "I need to find the average of the currency-column for the last 50 rows", you could use this:

=ArrayFormula(query({D2:E}; "select AVG(Col2) where (Col1 > date '"&TEXT(WORKDAY($D139:D;-50); "YYYY-MM-DD")&"' AND Col1 < date '"&TEXT($D139:D; "YYYY-MM-DD")&"') label AVG(Col2) ''"))

But then you say "I need this in every row for the 50 predecessor rows without copying the formula", so this is the best way I can think of having the formula in one cell:

={query({C2:C};"where Col1 is null limit 49";0);query(ARRAYFORMULA(if(E2:E="";"";(E2:E+E3:E+E4:E+E5:E+E6:E+E7:E+E8:E+E9:E+E10:E+E11:E+E12:E+E13:E+E14:E+E15:E+E16:E+E17:E+E18:E+E19:E+E20:E+E21:E+E22:E+E23:E+E24:E+E25:E+E26:E+E27:E+E28:E+E29:E+E30:E+E31:E+E32:E+E33:E+E34:E+E35:E+E36:E+E37:E+E38:E+E39:E+E40:E+E41:E+E42:E+E43:E+E44:E+E45:E+E46:E+E47:E+E48:E+E49:E+E50:E+E51:E)/50));"limit "&counta(E2:E)-49&" ";0)}

NOTE: the formula must go in row 2!! Anywhere else and it might cause issues with your sheet adding more rows.

For query({C2:C};"where Col1 is null limit 49";0) to work correctly and offset the arrayformula, you must have at least 49 blank cells. If not, reference a different column.

Since your sample sheet is location Germany, I've had to use ; rather than , as function separators.

Update

If you create a named range called 'RowsToAverage' containing the number of rows you want to average (ie. 50), here is a revised formula:

={query({C2:C};"where Col1 is null limit "&RowsToAverage-1&"";0);query(ARRAYFORMULA(if(E2:E="";"";(E2:E+E3:E+E4:E+E5:E+E6:E+E7:E+E8:E+E9:E+E10:E+E11:E+E12:E+E13:E+E14:E+E15:E+E16:E+E17:E+E18:E+E19:E+E20:E+E21:E+E22:E+E23:E+E24:E+E25:E+E26:E+E27:E+E28:E+E29:E+E30:E+E31:E+E32:E+E33:E+E34:E+E35:E+E36:E+E37:E+E38:E+E39:E+E40:E+E41:E+E42:E+E43:E+E44:E+E45:E+E46:E+E47:E+E48:E+E49:E+E50:E+E51:E)/RowsToAverage));"limit "&counta(E2:E)-(RowsToAverage-1)&" ";0)}

You'll still need to manually create the range (E2:E+E3:E+E4:E+E5:E+E6:E+E7:E+E8:E+E9:E+E10:E+E11:E+E12:E+E13:E+E14:E+E15:E+E16:E+E17:E+E18:E+E19:E+E20:E+E21:E+E22:E+E23:E+E24:E+E25:E+E26:E+E27:E+E28:E+E29:E+E30:E+E31:E+E32:E+E33:E+E34:E+E35:E+E36:E+E37:E+E38:E+E39:E+E40:E+E41:E+E42:E+E43:E+E44:E+E45:E+E46:E+E47:E+E48:E+E49:E+E50:E+E51:E), but his can be done easily in another cell, then copied into the formula above:

=textjoin("+";true;arrayformula("E"&row(indirect("A2:A"&RowsToAverage+1))&":E"))