Excel formula for trend? - excel

does any one can suggest me any formula in excel to use for following question.
I have a data list with historical numbers for each particular example. I would need in column G Categoraise in 3 Categories Increasing, Decreasing, Various:
For exmaple
Column A Column B Column C Column D Column E Column F Column G
month 1 month2 month3 month4 month5 Category
Example 1 3 1 2 0 4 Various
Example 2 6 4 3 1 0 Decreasing
Example 3 0 0 3 5 10 Increasing
I am not sure that trend focmula is a correct one.
Any kind suggestion?

Use nested IFS with SUMPRODUCT:
=IF(AND(SUMPRODUCT(--(B2:E2<C2:F2)),SUMPRODUCT(--(B2:E2>C2:F2))),"Various",IF(SUMPRODUCT(--(B2:E2<C2:F2)),"increasing",IF(SUMPRODUCT(--(B2:E2>C2:F2)),"decreasing","even")))

Here is a VBA solution which can be used directly on the worksheet:
Function ClassifySequence(nums As Range) As String
Dim i As Long, minDelta As Long, maxDelta As Long
Dim delta As Variant
With Application.WorksheetFunction
maxDelta = .Min(nums) - .Max(nums)
minDelta = -maxDelta
End With
For i = 1 To nums.Cells.Count - 1
delta = nums.Cells(i + 1).Value - nums.Cells(i).Value
If delta < minDelta Then minDelta = delta
If delta > maxDelta Then maxDelta = delta
Next i
If maxDelta <= 0 Then
ClassifySequence = "Decreasing"
ElseIf minDelta >= 0 Then
ClassifySequence = "Increasing"
Else
ClassifySequence = "Various"
End If
End Function
For example,
In this code I decided to classify a constant sequence as decreasing. That could of course be changed, either to "Various" or "Increasing" or by creating a fourth category as in Scott Craner's excellent answer.

Related

array from continuous data?

I have a quite difficult problem that i cant wrap my head around.. hope you can help me!
Lets say my data is in A1:G1 for example:
A1 B1 C1 D1 E1 F1 G1
X X 0 X X X 0
or
Y X X X X Z X
The thing i would need to come up with is how to get array from this data according to the X, BUT if like in example 1 there is 2 times X in the beginning and 3 x next to each other so the array should come out like {2;2;0;3;3;3;0} so i want the array to be 7 long and the array should show the x as number how many are next to each other.
example 2 should come out like {0;4;4;4;4;0;1}
if you can figure this out would really help me alot!
Edit:
Trying to give out better, more bigger picture of what i mean..
if data is :
A B C
1 X X
2 X X
3 X
it should come out as
A B C
1: 2 4 0
2: 0 4 2
3: 1 0 0
or in array {2\4\0;0\4\2;1\0\0}
on B1 and B2 there should be 4 because the formula should count horizontal but also vertical continuum. I tried to use usmanhaqs formula but i was not able to modify it so the count resets on every line.
Real size of the table is 7 times 7 cells.
I will use the array with another array (scoreboard which is also 7 times 7 cells, and has numbers 1, 2 or 3 on every cell) using sumproduct and it will give out the points of that player.
I appreciate your efforts on helping out a newbie learner on vba :)
For a formula solution, I can only come up with one for the special case where you have just X's and zeroes (example 1) so far:
=SUM(IF(A1:G1<>"X",0,INDEX(FREQUENCY(IF(A1:G1="X",COLUMN(A1:G1)),IF(A1:G1<>"X",COLUMN(A1:G1))),N(IF({1},SUBTOTAL(2,OFFSET(A1,0,0,1,COLUMN(A1:G1)))))+1,1)))
entered as an array formula using CtrlShiftEnter
I have wrapped it in a SUM function to demonstrate that it generates an array which can be passed to another function (result: 13) or it can be array-entered across several cells:
You can test this code
Function get_array(r As Range, match_chr As String)
Dim check_val
Dim array_value
array_value = "{"
For i = 1 To r.Count
check_value = r.Item(i)
If (check_value = match_chr) Then
j = i + 1
Do While (j <= r.Count) And (check_value = r.Item(j))
j = j + 1
Loop
array_value = array_value & WorksheetFunction.Rept(j - i & ", ", j - i)
i = j - 1
Else
array_value = array_value & "0, "
End If
Next
array_value = Left(array_value, Len(array_value) - 2) & "}"
get_array = array_value
End Function
You can use it as below
EDIT
find below another function to return an array of values that can be used in the formulae
Function get_number_array(r As Range, match_chr As String)
Dim check_val
Dim array_value
Dim number_array(1 To 50) As Long
For i = 1 To r.Count
check_value = r.Item(i)
If (check_value = match_chr) Then
j = i + 1
Do While (j <= r.Count) And (check_value = r.Item(j))
j = j + 1
Loop
For k = 1 To j - i
number_array(i + k - 1) = j - i
Next k
i = j - 1
Else
number_array(i) = 0
End If
Next
get_number_array = number_array
End Function
You have to use it same as the previous one, but it will return excel array.

Auto-increment based on other column repeats

I need a macro or formula that can do this:
Column A Values:
1
1
1
2
2
2
3
3
4
4
4
5
5
6
6
I need Column B to do:
1
2
3
1
2
3
1
2
1
2
3
1
2
1
2
Because column B has to have an increment number while column A has the same repeated value (for example 1 1 1 2), when it changes (to 2 or 3 etc.) the counter on column B has to reset and increment itself while A repeats the next value (1 2 3 1)
Thanks
Edit
Have a look at bzimor's answer as he solves is in a more general way without a hard value in column B1!
Original Answer
You can solve it the following way without VBA:
Put a hard value of 1 in column B1. This is your start value and should be always correct because you start counting with 1.
Then enter the following formula in B2
=IF($A2=$A1;$B1+1;1)
Just drag the formula down to the other rows of B and you're done
So B3 should look like this
=IF($A3=$A2;$B2+1;1)
and so on ...
You can use single formula:
=COUNTIF($A$1:A1,A1)
Put it into cell B1 and fill down
Here is your desired macros
Sub jkjainGenerateSerialNumber20161124()
readcol = Val(InputBox("type ref col#"))
writecol = Val(InputBox("type dest col#"))
ts = 0
Range("A1000000").Select
Selection.End(xlUp).Select
lastrow = ActiveCell.Row
For n = 2 To lastrow
prev = Cells(n - 1, readcol)
curr = Cells(n, readcol)
If prev <> curr Then
ts = 1
End If
If prev = curr Then
ts = ts + 1
End If
Cells(n, writecol) = ts
Next
End Sub

Excel for loop to get value from another row

I have an spreadsheet that contains various data. It looks like this:
A A A B B C C C C
a 1 2 3 2 1 4 2 3 2
b 0 2 3 3 0 1 2 3 0
c 6 6 3 0 2 1 0 4 0
etc.
What I want is to add all the Aa's and come up with a Aa total, all the Bb's and come up with a Bb total, all the Ab's etc.
What I want to do is, for every column, check if it is A, B or C. I want to do that because the data may change I might end up with four columns for A, two for B, etc. I know however that a, b and c will stay where they are.
I also don't know the order of A, B and C. There could be two A's followed by two C's and then one B.
My final result will be a table containing all the totals:
Aa Ab Ac
Ba Bb Bc
Ca Cb Cc
Where in the previous example would mean that Aa = 1 + 2 + 3 = 6, Ab = 5, etc.
Something like that.
I think the way to go is for 1-1 (the total of Aa's) is to go through every column in the first row. Check if it is an A. If it is, then get the value of the same column but second row. Add it to the total. When gone through all the columns, show up the total in 1-1.
What I have so far (for A):
Sub getA()
Dim x As Integer
Dim total As Integer
'cols = Find number of columns with data in them
For x = 1 To cols
'cell = cell in Ax
If InStr(1, cellvalue, "a") = 1 Then
'val = value from row 5 in same column
total = total + Val
End If
Next
End Sub
But I don't really know how to proceed with the commented lines.
Finally, another thing I would like to know is how will these values be presented in their respective cells without any extra event being carried (button for example). They should just appear in their cells from the moment someone opens the spreadsheet.
Any help is greatly appreciated.
Thanks.
Just an FYI, this can be done using the SUMPRODUCT formula:
=SUMPRODUCT(($B$1:$J$1=D$9)*($A$2:$A$4=$C10)*$B$2:$J$4)
EDIT
To compare the first letter then use this formula:
=SUMPRODUCT((LEFT($B$1:$J$1,1)=D$9)*($A$2:$A$4=$C10)*$B$2:$J$4)
Are you looking for something like:
Function countletter(strLetter As String) As Double
Dim x As Double, y As Double, xMax As Double, yMax As Double
xMax = Range("A1").CurrentRegion.Columns.Count
yMax = Range("A1").CurrentRegion.Rows.Count
For x = 1 To xMax
For y = 1 To yMax
If Cells(y, x).Value = strLetter Then
countletter = countletter + 1
End If
Next
Next
End Function

How to find which value creates maximum combination - Excel VBA

I need to find which value creates the maximum combination shown below in Excel Vba
suppose,
I have combinations like this
a a+b a+b+c 1 1+2 1+2+1 3 4
b a+c a+b+d 2 1+1 1+2+3 2 6
c a+d a+b+e 1 1+3 1+2+2 4 5
d a+e a+c+d 3 1+2 1+1+3 3 5
e b+c a+c+e 2 2+1 1+1+2 3 4
b+d a+d+e 2+3 1+3+2 5 6
b+e b+c+d 2+2 2+1+3 4 6
c+d b+c+e 1+3 2+1+2 4 5
c+e b+d+e 1+2 2+3+2 3 7
d+e c+d+e 3+2 1+3+2 5 6
I need to find which combinations creates maximum value, In this case the value "7" is maximum which is created by 2,3,2. Hence I want these value as a output in unique cells.
I may have thousands of combinations, hence i want these to be found automatically and to be output in unique cells automatically and run the program further.
Please help.
Thanks
Balaji
Concept :
The greatest sum of m values within a set of n is the sum of the m bigger values.
Once the values are ordered in descending order, the solution is trivial.
Here is a pure Excel solution, without VBA.
Design & Implementation :
The user input (variable names and values) are in C4:D8.
The idea is the following:
Determine the order of data. For this, I use RANK in the column B.
Then use VLOOKUP in columns G and H to sort the data according to rank.
Then the maximum sums are trivial to compute in : sum of the n bigger numbers.
Here is the code:
A B C D E F G H I J K
1
2 User input Sorted by rank Maximum sums
3 Rank name value Rank name value name value
4 =RANK.EQ(C4;$C$4:$C$8) a 45 1 =VLOOKUP(E4;$A$4:$C$8;2;FALSE) =VLOOKUP(E4;$A$4:$C$8;3;FALSE) 2 numbers =CONCATENATE($F$4;"+";$F$5) =$G$4+$G$5
5 =RANK.EQ(C5;$C$4:$C$8) b 1 2 =VLOOKUP(E5;$A$4:$C$8;2;FALSE) =VLOOKUP(E5;$A$4:$C$8;3;FALSE) 3 numbers =CONCATENATE($F$4;"+";$F$5;"+";$F$6) =$G$4+$G$5+$G$6
6 =RANK.EQ(C6;$C$4:$C$8) c 2 3 =VLOOKUP(E6;$A$4:$C$8;2;FALSE) =VLOOKUP(E6;$A$4:$C$8;3;FALSE) 4 numbers =CONCATENATE($F$4;"+";$F$5;"+";$F$6;"+";$F$7) =$G$4+$G$5+$G$6+$G$7
7 =RANK.EQ(C7;$C$4:$C$8) d 12 4 =VLOOKUP(E7;$A$4:$C$8;2;FALSE) =VLOOKUP(E7;$A$4:$C$8;3;FALSE) 5 numbers =CONCATENATE($F$4;"+";$F$5;"+";$F$6;"+";$F$7;"+";$F$8) =$G$4+$G$5+$G$6+$G$7+$G$8
8 =RANK.EQ(C8;$C$4:$C$8) e 33 5 =VLOOKUP(E8;$A$4:$C$8;2;FALSE) =VLOOKUP(E8;$A$4:$C$8;3;FALSE)
Here is how the result looks:
A B C D E F G H I J K
1
2 User input Sorted by rank Maximum sums
3 Rank name value Rank name value name value
4 1 a 45 1 a 45 2 numbers a+e 78
5 5 b 1 2 e 33 3 numbers a+e+d 90
6 4 c 2 3 d 12 4 numbers a+e+d+c 92
7 3 d 12 4 c 2 5 numbers a+e+d+c+b 93
8 2 e 33 5 b 1
Note that it can be easily extended to more variables.
Expanding on d-stroyer's answer, and converting it to VBA:
create UDF:
Option Explicit
Function GetMax(RNames As Range, RVals As Range, MaxNums As Long) As String
Dim i As Long
Dim j As Long
Dim tmpName As String
Dim tmpVals As Long
Dim Names()
Dim Vals()
Names = RNames
Vals = RVals
For i = 1 To UBound(Names) - 1 'bubble sort
For j = i + 1 To UBound(Names)
If Vals(i, 1) < Vals(j, 1) Then 'largest first
tmpName = Names(i, 1)
Names(i, 1) = Names(j, 1)
Names(j, 1) = tmpName
tmpVals = Vals(i, 1)
Vals(i, 1) = Vals(j, 1)
Vals(j, 1) = tmpVals
End If
Next j
Next i
For i = 1 To MaxNums
If Vals(i, 1) <= 0 Then Exit For
'adding zero, or negative numbers will lower the total
Next i
For j = 1 To i - 1
GetMax = GetMax & Names(j, 1) & ","
'now we know how many values to use (from previous loop)
'make the string up
Next j
If Len(GetMax) > 0 Then
GetMax = Left(GetMax, Len(GetMax) - 1)
'remove the final comma
Else
GetMax = "No result found"
End If
End Function
Call using =getmax(A1:A5,D1:D5,3)
result would be d,b,e
I'll leave the rest up to you ov checking for error conditions, such as more than 1 column passed in the range, or ranges of unequal size, or a max # of items returned being larger than the range size

Auto calculate average over varying number values row by row

I have an Excel file with several columns in it and many rows. One column, say A has ID numbers. Another column, say G has prices. Column A has repeating ID numbers, however not all numbers repeat the same amount of times. Sometimes just once, other times 2, 3 or several times. Each column G for that row has a unique price.
Basically, I need to average those prices for a given ID in column A. If each ID was repeated the same number of times, this would be quite simple, but because they are not I have to manually do my average calculation for each grouping. Since my spreadsheet has many many rows, this is taking forever.
Here is an example (column H is the average that I am currently calculating manually):
A ... G H
1 1234 3.00 3.50
2 1234 4.00
3 3456 2.25 3.98
4 3456 4.54
5 3456 5.15
11 8890 0.70 0.95
13 8890 1.20
...
So in the above example, the average price for ID# 1234 would be 3.50. Likewise, the average price for ID# 3456 would be 3.98 and for #8890 would be 0.95.
NOTICE how rows are missing between row 5 and 11, and row 12 is missing too? That is because they are filtered out for some other reason. I need to exclude those hidden rows from my calculations and only calculate the average for the rows visible.
Im trying to write a VBA script that will automatically calculate this, then print that average value for each ID in column H.
Here is some code I have considered:
Sub calcAvg()
Dim rng As Range
Set rng = Range("sheet1!A1:A200003")
For Each Val In rng
Count = 0
V = Val.Value '''V is set equal to the value within the range
If Val.Value = V Then
Sum = Sum + G.Value
V = rng.Offset(1, 0) '''go to next row
Count = Count + 1
Else
'''V = Val.Value '''set value in this cell equal to the value in the next cell down.
avg = Sum / Count
H = avg '''Column G gets the avg value.
End If
Next Val
End Sub
I know there are some problems with the above code. Im not too familiar with VBA. Also this would print the avg on the same line everytime. Im not sure how to iterate the entire row.
This seems overly complicated. Its a simple problem in theory, but the missing rows and differing number of ID# repetitions makes it more complex.
If this can be done in an Excel function, that would be even better.
Any thoughts or suggestions would be greatly appreciated. thanks.
If you can add another row to the top of your data (put column Headers in it) its quite simple with a formula.
Formula for C2 is
=IF(A2<>A1,AVERAGEIFS(B:B,A:A,A2),"")
copy this down for all data rows.
This applies for Excel 2007 or later. If using Excel 2003 or earlier, use AVERAGEIF instead, adjusting ranges accordingly
If you can't add a header row, change the first formula (cell C1) to
=AVERAGEIFS(B:B,A:A,A1)
In my way ..
Sub calcAvg()
Dim x, y, i, y2, t, Count, Mount As Integer
Dim Seek0 As String
x = 1 '--> means Col A
y = 1 '--> means start - Row 1
y2 = 7 '--> means end - Row 19
For i = y To y2
If i = y Then
Seek0 = Cells(i, x)
t = i
Count = Cells(i, x + 6)
Mount = 1
Else
If Cells(i, x) <> Seek0 Then
Cells(t, x + 7) = Count / Mount
Count = Cells(i, x + 6)
Mount = 1
t = i
Seek0 = Cells(i, x)
Else
Count = Count + Cells(i, x + 6)
Mount = Mount + 1
End If
End If
Next
End Sub
Hope this helps ..

Resources