0

since STDEV is not supported under ARRAYFORMULA there is either draggable solution:

enter image description here

or hardcoded solution:

enter image description here

but neither of them is dynamically scalable so is there any workaround?

from a quick google search, it looks like no one dared to dream of such lengths

data sample:

b   5
a   1
a   2
b   5
a   1

desired result:

a   0.5773502692
b   0
player0
  • 124,011
  • 12
  • 67
  • 124

2 Answers2

2

the math says that standard deviation can be achieved as:

enter image description here

if we substitute for formulae we get:

enter image description here

knowing the above we can easily convert it into a multidimensional array... let's start with the first query where we pivot labels:

enter image description here

removing labels:

enter image description here

calculating the average:

enter image description here

removing labels:

enter image description here

for subtraction, we need to exclude empty cells so we use IF:

enter image description here

and raise it on the 2nd power:

enter image description here

now we can sum it up per column with MMULT or QUERY again:

enter image description here

to make it more dynamic we can construct query selection with SEQUENCE:

enter image description here

next is division by count:

enter image description here

then square root:

enter image description here

now we just add back labels:

enter image description here

and transpose it:

=ARRAYFORMULA(TRANSPOSE({INDEX(QUERY({A:B}, 
 "select max(Col2) where Col1 is not null group by Col2 pivot Col1"), 1); 
 (QUERY(QUERY(IF(QUERY(QUERY({A:B, ROW(A:A)}, 
 "select max(Col2) where Col2 is not null group by Col3 pivot Col1"), "offset 1", )="",,
 (QUERY(QUERY({A:B, ROW(A:A)}, 
 "select max(Col2) where Col2 is not null group by Col3 pivot Col1"), "offset 1", )-
 QUERY(QUERY({A:B, ROW(A:A)/0}, 
 "select avg(Col2) where Col2 is not null group by Col3 pivot Col1"), "offset 1", ))^2), 
 "select "&TEXTJOIN(",", 1, "sum(Col"&SEQUENCE(COUNTUNIQUE(A:A))&")")), "offset 1", )/
 (INDEX(TRANSPOSE(QUERY({A:B}, 
 "select Col1,count(Col1) where Col1 is not null group by Col1 label count(Col1)''")), 2)-1))^(1/2)}))

enter image description here



it works, but we can do better... simple IF statement will do:

enter image description here

but to make it fast and smart we need some tweaks to counter empty cells and unsorted dataset:

enter image description here

we add errors:

enter image description here

subtract the average:

enter image description here

raise on the 2nd power:

enter image description here

remove errors with IFNA and sum it:

enter image description here

divide by count-1:

enter image description here

take a square root:

enter image description here

transpose it and add back labels:

=INDEX(IFERROR({SORT(UNIQUE(FILTER(A:A, A:A<>""))), FLATTEN(( 
 INDEX(QUERY(IFNA((IF(FILTER(A:A, A:A<>"")=TRANSPOSE(SORT(UNIQUE(
 FILTER(A:A, A:A<>"")))), FILTER(B:B, B:B<>""), NA())-INDEX(QUERY({A:B, ROW(A:A)/0}, 
 "select avg(Col2) where Col2 is not null group by Col3 pivot Col1"), 2))^2), 
 "select "&TEXTJOIN(",", 1, "sum(Col"&SEQUENCE(COUNTUNIQUE(A:A))&")")), 2)/TRANSPOSE(QUERY({A:B}, 
 "select count(Col1) where Col1 is not null group by Col1 label count(Col1)''")-1))^(1/2))}))

enter image description here

player0
  • 124,011
  • 12
  • 67
  • 124
1

new alternative:

=BYROW(D1:D2, LAMBDA(xx, STDEV(FILTER(B:B, A:A=xx))))

enter image description here

or all in one fx:

={UNIQUE(FILTER(A:A, A:A<>"")), 
 BYROW(UNIQUE(FILTER(A:A, A:A<>"")), LAMBDA(xx, STDEV(FILTER(B:B, A:A=xx))))}

enter image description here

player0
  • 124,011
  • 12
  • 67
  • 124