Using an Array to get the average of a selection of numbers - arrays

I have 12 different numbers on a row in an excel sheet (repeated few times on different row) and I would like to get the average of the 8 bigger numbers (4 numbers won't be used). I thought to use an array, but how to select the 8 bigger numbers in this array?
I would like to do it in VBA. Do you have any ideas/directions how to proceed, because I am not really sure how to start.
Example: 12,3,5,6,8,11,9,7,5,8,10,1 (Results=8.875), if I didn't make a mistake!
Thanks.

I know you asked for VBA, but here's a formula. If this works, you can quickly throw in VBA (use the macro recorder to see how if you're unsure).
If that's in row 1, you can use:
=AVERAGE(LARGE(A1:L1,{1,2,3,4,5,6,7,8}))
You should be able to change A1:l1 to be the range where your numbers are, i.e.
=AVERAGE(LARGE(A1:F2,{1,2,3,4,5,6,7,8}))
Edit: Per your comment, also no need for VBA. Just use conditional highlighting. Highlight your range of numbers, then go to Conditional Highlighting --> Top/Bottom Rules --> Top 10 Items. Then just change the 10 to 8, and choose a color/format. Then Apply!
(each row in the above is treated as it's own range).
Edt2: bah, my image has duplicate numbers which is why the top 8 rule is highlighting 9 numbers sometimes. If you request I'll try to edit and tweak

You can use a simple Excel function to compute the answer
=AVERAGE(LARGE(A1:L1, {1,2,3,4,5,6,7,8}))
It is a bit more complex in VBA, but here is a function that does the same computation (explicit typing per Mat's Mug):
Public Function AvgTop8(r As Range) As Double
Dim Sum As Double, j1 As Integer
For j1 = 1 To 12
If WorksheetFunction.Rank(r(1, j1), r) <= 8 Then
Sum = Sum + r(1, j1)
End If
Next j1
AvgTop8 = Sum / 8#
End Function
The Excel RANK function returns the rank of a number in a list of numbers, with the largest rank 1 and so on. So you can search through the 12 numbers for the 8 largest, sum them and divide by 8.

You don't need VBA for this. You can use:
=AVERAGE(LARGE(A1:L1,{1;2;3;4;5;6;7;8}))

Related

Multiply two ranges in Excel to get an array result

Excel 365 allows to multiply ranges to get an array as a result.
Example:
#
A
B
C
1
1
0
1
2
0
1
1
Entering in A3
= A1:C1 * A2:C2
will evaluate to {1,0,1} * {0,1,1}
and return an array {0,0,1} spilling in A3:C3
#
A
B
C
3
0
0
1
This operation can also be used in formulas, especially useful in FILTER(), SUMPRODUCT() etc.
Is there a formula in Excel 365 that can take as arguments an arbitrary number of 1-D ranges, multiply them, and return a 1-D array in the same way as above?
For what I found out so far, SUMPRODUCT() and MMULT() can return only a single value, not a 1-D array.
Alternatively, I can write a LAMBDA, but would like to avoid it, if there is a ready-made formula for it.
I am not 100% what do you mean, I would assume you want to multiply all rows of the same column and return a row array with the result per column. You can achieve it in cell E1 using the following formula:
=BYCOL(A1:C3, LAMBDA(col, PRODUCT(col)))
and here is the output:
If you have only positives numbers, then you can use MMULT, based on the following mathematical properties:
Putting in excel terms using EXP/LN functions in our case it would be:
=EXP(MMULT(TOROW(ROW(A1:C3)/ROW(A1:C3)), LN(A1:C3)))
or using LET to avoid repetitions:
=LET(rng, A1:C3, rows, ROW(rng), u, TOROW(rows/rows), EXP(MMULT(u, LN(rng))))
You get the same result.
Note: rows/rows just returns the unit vector with the same number of rows as A1:C3.

How to count for 2 different arrays how many times the elements are repeated, in MATLAB?

I have array A (44x1) and B (41x1), and I want to count for both arrays how many times the elements are repeated. And if the repeated values are present in both arrays, I want their counting to be divided (for instance: value 0.5 appears 500 times in A and 350 times in B, so now divide 500 by 350).
I have to do this for bigger arrays as well, so I was thinking about using a looping (but no idea how to do it on MATLAB).
I got what I want on python:
import pandas as pd
data1 = pd.read_excel('C:/Users/Desktop/Python/data1.xlsx')
data2 = pd.read_excel('C:/Users/Desktop/Python/data2.xlsx')
for i in data1['Mag'].value_counts() & data2['Mag'].value_counts():
a = data1['Mag'].value_counts()/data2['Mag'].value_counts()
print(a)
break
Any idea of how to do the same on MATLAB? Thanks!
Since you can enumerate all valid earthquake magnitude values, you could use:
% Make up some data
A=randi([2 58],[100 1])/10;
B=randi([2 58],[20 1])/10;
% Round data to nearest tenth
%A=round(A,1); %uncomment if necessary
%B=round(B,1); %same
% Divide frequencies
validmags=0.2:0.1:5.8;
Afreqs=sum(double( abs(A-validmags)<1e-6 ),1); %relies on implicit expansion; A must be a column vector and validmags must be a row vector; dimension argument to sum() only to remind user; double() not really needed
Bfreqs=sum(double( abs(B-validmags)<1e-6 ),1); %same
Bfreqs./Afreqs, %for a fancier version: [{'Magnitude'} num2cell(validmags) ; {'Freq(B)/Freq(A)'} num2cell(Bfreqs./Afreqs)].'
The last line will produce NaN for 0/0, +Inf for nn/0, and 0 for 0/nn.
You could also use uniquetol, align the unique values of each vector, and divide the respective absolute frequencies. But I think the above approach is cleaner and easier to understand.

Issues with SUMPRODUCT in Excel: Trying to count the number of average subtractions above a given threshold

I have a fairly simple issue that I cannot seem to work out. It may be familiar to some of you now.
I have the following matrix (which I will refer to as two arrays):
F G H I J ... R S T U V
1 0 0 1 1
4 4 2 3 5 1 2 3 1 2
2 2 3 1 2 0 1
2 1 0 0 4 0 0 3 0 0
I would like to take the difference between the average of each row in array 1 (columns F:J) and the average of each row in array 2 (columns R:V). For example, the average of F2:J2 = 3.6, the average of R2:V2 = 1.8, and the overall difference = 1.8. I would then like to count the number of overall differences which exceed a given threshold (e.g., 1), but I want to ignore rows which have no entries (see R1:V1) and/or partially missing entries (see the 2nd entry in row F3:J3 and 4th and 5th entry in row R3:V3).
I was lucky enough to be introduced to array formulae by #Tom Sharpe, and have attempted to adapt his code for a similar issue I had, e.g.,:
=SUMPRODUCT(--((SUBTOTAL(1,OFFSET(F1,ROW(F1:F4)-ROW(F1),0,1,COLUMNS(F1:J1)))-SUBTOTAL(1,OFFSET(R1,ROW(R1:R4)-ROW(R1),0,1,COLUMNS(R1:V1)))>1)*(SUBTOTAL(2,OFFSET(F1,ROW(F1:F4)-ROW(F1),0,1,COLUMNS(F1:J1)))=COLUMNS(F1:J1))*(SUBTOTAL(2,OFFSET(R1,ROW(R1:R4)-ROW(R1),0,1,COLUMNS(R1:V1)))=COLUMNS(R1:V1))>0))
From what I understand, the code attempts to count the number of differences between the averages of each row in each array that exceed 1, so long as the product between the number of columns with full entries is >0 (i.e. has full data). However, it keeps throwing the #DIV/0! error, which I believe stems from that fact that it is still trying to subtract the average of F1:J1 and R1:V1 (e.g., the empty row), which would produce this kind of error. The correct answer for the current example is 1 (e.g., F2:J2 [3.6] - R2:V2 [1.8] = 1.8 == 1.8 > 1).
Does anyone have any ideas as to how the code can be attempted for the current purposes, and perhaps a v. brief explanation of what is going awry in the current code?
You're right, SUBTOTAL falls over when it's trying to find the average of an range containing only empty cells.
If you want to persevere and try and do it the same way as before with an array formula, you have to turn it round and put the condition for all the cells in both ranges to be non-blank in an if statement so that it doesn't try and take the average unless both ranges have no blanks:
=SUM(IF((SUBTOTAL(2,OFFSET(F1,ROW(F1:F4)-ROW(F1),0,1,COLUMNS(F1:J1)))=COLUMNS(F1:J1))*(SUBTOTAL(2,OFFSET(R1,ROW(R1:R4)-ROW(R1),0,1,COLUMNS(R1:V1)))=COLUMNS(R1:V1)),
--(SUBTOTAL(1,OFFSET(F1,ROW(F1:F4)-ROW(F1),0,1,COLUMNS(F1:J1)))-SUBTOTAL(1,OFFSET(R1,ROW(R1:R4)-ROW(R1),0,1,COLUMNS(R1:V1)))>1)))
This time unfortunately I found I couldn't SUMPRODUCT it - I think this is because of the presence of the IF statement - so you have to enter it as an array formula using CtrlShiftEnter
Will this work for you?
=IF(NOT(OR(IFERROR(MATCH(TRUE,ISBLANK(F1:J1),0),FALSE),IFERROR(MATCH(TRUE,ISBLANK(R1:V1),0),FALSE))), SUBTOTAL(1,F1:J1)-SUBTOTAL(1,R1:V1), "Missing Value(s)")
My approach was a little different from what you tried to adapt from #TomSharp in that I'm validating the cells have data (not blank) and then perform the calculation, othewise return an error message. This is still an array function call, so when you enter the formulas, press ctrl+shft+enter.
The condition part of the opening if() checks to see that each range's cells are not blank: if a match( true= isblank(cell))
means a cell is blank (bad), if no match ... ie no blank cells, Match will return an #NA "error" (good). False is good = Errors found ? No. ((ie no blank cells))

Excel: How to check for repeated numbers inside a cell

I have an excel spreadsheet with numbers from 000 to 999 and am trying to find repeated numbers inside a cell.
(So for example, printing 1 if the number is 022 , 555 or 115 and 0 if it isn't)
So far, I have not been able to find a solution.
Feel free to ask for more information and thanks in advance.
This will do: =IF(COUNT(SEARCH(REPT({0,1,2,3,4,5,6,7,8,9},2),A1))>0,1,0)
Note: If value in cell A1 contains 2 repeated digits it will show 1 else 0. You can customize the repetition limit by changing 2 in the part 8,9},2).
You could try this one if you wanted to find repeated digits not necessarily next to each other:-
=IF(MAX(LEN(A1)-LEN(SUBSTITUTE(A1,{0,1,2,3,4,5,6,7,8,9},"")))>1,1,0)
If the numbers are stored as 3-digit numbers and you wanted it to work for (e.g.) 001, would need:-
=IF(MAX(LEN(TEXT($A1,"000"))-LEN(SUBSTITUTE(TEXT($A1,"000"),{0,1,2,3,4,5,6,7,8,9},"")))>1,1,0)
If your data is in Range "A1:A100" and you want to locate repeated numbers in the range for instance, enter =IF(COUNTIF(A:A,A1)>1,1,0) in cell B1 and fill down. But if you want to check repetitions of specific numbers like 022, 555 or 115, enter =IF(OR(AND(A1=022,COUNTIF(A:A,A1)>1),AND(A1=555,COUNTIF(A:A,A1)>1),AND(A1=115,COUNTIF(A:A,A1)>1)),1,0) in cell B1 and fill down.
being a number, use arithmetics to break it into digits and then check if all are different.
the formula is
=INT(NOT(AND(INT(A1/100)<>INT(MOD(A1,100)/10),INT(A1/100)<>MOD(A1,10),INT(MOD(A1,100)/10)<>MOD(A1,10))))
let's analyze it step by step
first, INT(A1/100) extracts the first digit (the integer division by 100); then INT(MOD(A1,100)/10) extracts the second digit (the integer division by 10 of the modulo 100); and MOD(A1,10) extracts the last digit (the modulo 10).
next there are the three comparisons of difference <> first with second, second with third and first with third, combined with AND() and finally take the result, negate it NOT() and transforming it into an integer 0 or 1 with INT()

Excel average rows to array formula

I want to take the average of rows which would result in a column (array). Example input:
3 4
4 4
4 6
With an array formula I want to create:
3.5
4
5
The average is the sum of numbers divided by the count of that numbers.
So first add them (A1:A3+B1:B3)
3+4 = 7
4+4 = 8
4+6 = 10
Then divide by the number of numbers(/2):
7/2 = 3.5
8/2 = 4
10/2 = 5
{=(A1:A3+B1:B3)/2}
edit after comment from op:
formula for addition without adding column manually from https://productforums.google.com/forum/#!topic/docs/Q9x44sclzfY
{=mmult(A1:B3,sign(transpose(column(A1:B3))))/Columns(A1:B3)}
This is one way to do that in Excel
=SUBTOTAL(1,OFFSET(A1:B3,ROW(A1:B3)-MIN(ROW(A1:B3)),0,1))
OFFSET supplies an "array of ranges", each range being a single row, and SUBTOTAL with 1 as first argument, averages each of those ranges. You can use this in another formula or function or entered in a range on the worksheet.
The advantage over Siphor's suggestion with MMULT is that this will still work even with blanks or text values in the range (those will be ignored)
If first column is A and the second is B, then enter this formuls in column C:
=AVERAGE(A1,B1)
and extend it to the last row
Also you can use a range if you have more than 2 columns (this function allows for some cells to be empty):
=AVERAGE(A1:F1)

Resources