Excel not recognizing values as equal - excel

I have a table of values that I am trying to pull a number from by using a for loop that chooses the right table column based a value that was input into my spreadsheet. The input value (FvX2) is rounded to the nearest tenths place using the Ceiling function. This is then compared to values in the table by increasing the column number until the rounded value in the table equals the rounded number input into the spreadsheet. My problem is excel will not recognize when the two values are equal and never returns a value for Fvcl. I think this has something to do with the ceiling function but don't know how to get around it. Any ideas? Input value is 0.52 and is rounded to 0.6. Table values start at 0.1 and increase to 0.6 by increments of 0.1. Excel will not return Fvcl when FvX2 equals table value.
Dim FvX1 As Double
Dim FvX2 As Double
Dim Fvcl As Double
FvX2 = WorksheetFunction.Ceiling(Worksheets("Sheet1").Range("B7").Value, 0.1)
FvX1 = FvX2 - 0.1
For j = 0 To 5
If Worksheets("Tables").Cells(11, 2 + j).Value = FvX2 Then
Fvcl = 2 + j
End If
Next j

Related

How to get sum value from start time and end time?

I have a start time, duration and a data value in Columns A, B and C respectively.
How can I capture the data that falls during the start time and end time and insert the sum of this data in a 30-minute cycle (e.g. 09:00, 09:30, 10:00, 10:30 etc) in the "Output" column?
For example, if Data_A had a start time was at 09:15 and end time at 10:15, its value would be returned at 09:00, 09:30 and 10:00.
If more than 1 data value was received within the same 30-minute cycle, the values would be summed.
For example, Data_A has a value of 0.1 and Data_B has a value of 0.2.
Data_B has a start time at 09:50 and end time at 10:10. The sum values at 09:00, 09:30 and 10:00 would be 0.1, 0.3 and 0.3 respectively.
If no data was received for any 30-minute cycle, it simply returns a zero.
The following SUMIFS function can be used to sum the values at start time but I couldn't modify it to take into account the duration and end time.
=SUMIFS($C$2:$C$10,$A$2:$A$10,">="&G2,$A$2:$A$10,"<"&G2+TIME(0,29,59))
The dataset I have is over a year's worth, I am open to solutions using cell equations or VBA.
Link to dropbox file
I would create a VBA function SumBetweenDateTimeLoop with inputs the cell of the starting datetime, the range of starting time, range of ending time, range of values to add and minutes of the loop (in this case fixed to 30).
Public Function SumBetweenDateTimeLoop(this_date As Range, dt_start As Range, dt_end As Range, values As Range, min_loop As Integer)
Dim i As Integer
Dim v As Double
Dim d1 As Date, d2 As Date
Dim v1 As Date, v2 As Date
If dt_start.Count <> dt_end.Count Or values.Count <> dt_end.Count Or dt_start.Count <> values.Count Then
Call MsgBox("Length of ranges have to be the same.")
Exit Function
End If
v = 0
For i = 1 To dt_start.Count
d1 = CDate(dt_start(i))
d2 = CDate(dt_end(i))
v1 = CDate(this_date)
v2 = DateAdd("n", min_loop, v1)
If Not ((d1 < v1 And d2 < v1) Or (d1 > v2 And d2 > v2)) Then
v = v + CDbl(values(i))
End If
Next i
SumBetweenDateTimeLoop = v
End Function
The result is reported in the red column (there are some differences from your green column but it should be correct if I understood correctly your problem).
In order to call the function (after have copied it into a module in VBA), type in the desired Excel cell the following request.
=SumBetweenDateTimeLoop(G2;A$2:A$10;E$2:E$10;C$2:C$10;30)
Code explanation
The idea is to define extremes of the cycle, so define v1 as the datetime in column G and v2 = v1+min_loop.
Then make a loop over the cells of the ranges (Excel columns A, E and C), define the extremes of datetime (d1 start datetime in column A and d2 ending datetime in column E) and check whether or not both d1 and d2 are lower than v1 or greather than v2.
If this condition is not satisfied, it means that at least a part of the time is inside the desired cycle and then add the relative value to the incremental parameter v, which at the end will be the return of the function.
It's not that difficult: the solution is 48 :-)
By this I mean that, in Excel, and entire day is one unit (e.g. 01/01/2022 + 1 = 02/01/2022).
As a result, one hour equals 1/24th and half an hour (30 minutes) corresponds with 1/48th of a day.
So, you want to round down to 1/48, which you can do using this simple formula:
=FLOOR(B2*48,1)/48
Hereby some examples:

Excel Sumproduct counts rows incorrectly with multiple column criteria

I am trying to calculate Precision and Recall for the output of a model which makes 3 predictions whether a person's name is John or not.
The ground truth for each entry/row is column A. The predictions are stored in columns O,Q and S. The model only needs 2 out of 3 predictions to be > 50% each to be considered correct.
Therefore a True Positive is when >=2 of O,Q,S are > 50%.
Similarly, a False Negative is when < 2 of O,Q,S are > 50%.
Precision = TP / (TP + FP)
Recall = TP / (TP + FN)
I can calculate precision ok because the final logic operator is >= and therefore the values cannot be 0 to be counted. But for this, the final SUM in the denominator is problematic, counting all rows.
This is the part that works, the Precision:
SUM(IF((A2:A300="John")*((O2:O300>=.5)+(Q2:Q300>=.5)+(S2:S300>=.5))>=2,1)) / (SUM(IF((A2:A300="John")*((O2:O300>=.5)+(Q2:Q300>=.5)+(S2:S300>=.5))>=2,1)) + (SUM(IF((A2:A300="Not John")*((O2:O300>=.5)+(Q2:Q300>=.5)+(S2:S300>=.5))>=2,1)))
And this is what I'm trying but doesn't work. The last < operator screws up the denominator and I can't figure out how to fix:
SUM(IF((A2:A300="John")*((O2:O300>=.5)+(Q2:Q300>=.5)+(S2:S300>=.5))>=2,1)) / (SUM(IF((A2:A300="John")*((O2:O300>=.5)+(Q2:Q300>=.5)+(S2:S300>=.5))>=2,1)) + (SUM(IF((A2:A300="John")*((O2:O300>=.5)+(Q2:Q300>=.5)+(S2:S300>=.5))<2,1)))
If there are 3 rows where A = "John" with only 2 of those rows have 2 of O,Q,S > 50%
And if there are 3 rows where A = "Not John" with all 3 rows have O,Q,S > 50%
Then,
Precision = 2 / (2 + 3) = 2/5
Recall = 2 / (2 + 1) = 2/3
You can fix the recall by putting an extra set of brackets round the <2 comparison:
=SUM(IF((A2:A7="John")*((O2:O7>=0.5)+(Q2:Q7>=0.5)+(S2:S7>=0.5))>=2,1))/(SUM(IF((A2:A7="John")*((O2:O7>=0.5)+(Q2:Q7>=0.5)+(S2:S7>=0.5))>=2,1))+(SUM(IF((A2:A7="John")*(((O2:O7>=0.5)+(Q2:Q7>=0.5)+(S2:S7>=0.5))<2),1))))
so you avoid multiplying by zero for the 'Not John' rows before doing the comparison and get the correct denominator.

generate random numbers between 0 and 1 in 10 cells in the row , in which the sum of the random number always equal to 7

How can I generate random numbers 0 or 1 in 10 cells in the row, in which the sum of the random number is always equal to 7?
enter image description here
Here's a way to get seven "1"s and three "0"s in random order using RAND and RANK
In A1:J1: =RAND()
In A2:J2: =IF(RANK(A1,$A$1:$J$1,1)>3,1,0)
Available here is a version that I really think works! https://www.dropbox.com/s/ec431fu0h0fhb5i/RandomNumbers.xlsx?dl=0
And here's the '0 and 1' version (sheet 2 at the above link):
De-dup Rankings Randoms First Cut Sorted
0.47999002 7 0.479992063 1 1
0.68823003 3 0.688233075 1 1
0.07594004 9 0.075938331 1 1
0.02077005 10 0.020766892 1 0
0.69217006 2 0.692170173 1 0
0.73355007 1 0.733549516 1 1
0.51546008 6 0.515462872 1 1
0.62308009 4 0.623078278 0
0.33033001 8 0.330331577 1
0.561260011 5 0.561260557 1
Formulae for columns A-C exactly as before, D is just 7 1's, E is:
=VLOOKUP(ROW(E2)-1,B$1:D$11,3,FALSE)
Assuming that you want a list of positive random numbers that add to 7 you can use this following method.
Enter a 0 in the top-left cell (Blue Cell).
Enter =RAND()*7 into the next 9 cells below the 0 (Orange Cells).
Enter a 7 in the cell below the 9 random values (Blue Cell).
Copy the 9 random values and paste-special-values over top to turn the formulas into values.
Sort just these 9 cells in ascending order
In the cell just to the right of the first random value put a formula that subtracts the cell to the left and one above from the cell to the left (Yellow Cells).
Repeat this formula down to the cell next to the 7 that was typed in.
Sum the values in the second column (Green Cell).
That should give you 10 random values whose sum is exactly 7.
The only issue is that getting the values to be between 0 and 1 will take a bit of trial and error.
It appears that trial and error may not be practical. It's about a one in 2,710 times that this list will contain only numbers between 0 and 1. Not overly practical. Sorry.
To answer the question in the post, enter this in A1:J1 as an array formula (ctrl+shift+enter):
=1-(TRANSPOSE(MOD(SMALL(RANDBETWEEN(0,1e12*(ROW(INDIRECT("1:10"))>0))+(ROW(INDIRECT("1:10"))-1)/10,ROW(INDIRECT("1:10"))),1))>0.65)
To answer the question in the post title, do the following:
In A1:J1 enter:
=RAND()
In K1 enter:
=IF(SUM(A1:J1)<7,(7-SUM(A1:J1))/(COUNT(A1:J1)-7),7/SUM(A1:J1))
In L1 enter:
=IF(SUM($A1:$J1)<7,(A1+$K1)/($K1+1),A1*$K1)
Fill over to U1.
I believe the 10 numbers generated will be identically distributed in [0,1), but obviously not uniformly (I'm fairly certain the distribution does not have a name). The numbers can't be considered independent. A few statistics on the distribution:
Mean: 0.7 (as expected)
The other statistics are estimated from 10,000 simulations:
Variance: 0.0295
Kurtosis: -0.648
Skewness: -0.192
Think of it as drawing a sample of size 7 from the set {1, 2, ..., 10}. The 1s correspond to the numbers chosen for inclusion in the sample. Here is some VBA code which generates such samples:
Function sample(n As Long, k As Long) As Variant
'returns a variant of length n
'consisting of k 1s and n-k 0s
'thought of as a sample of {1,...,n} of size k
Dim v As Variant 'vector to hold sample
Dim numbers As Variant
Dim i As Long, j As Long, temp As Long
ReDim v(1 To n)
ReDim numbers(1 To n)
For i = 1 To n
v(i) = 0
numbers(i) = i
Next i
'do k steps of a Fisher-Yates shuffle on numbers
For i = 1 To Application.WorksheetFunction.Min(k, n - 1)
j = Application.WorksheetFunction.RandBetween(i, n)
If i < j Then 'swap
temp = numbers(i)
numbers(i) = numbers(j)
numbers(j) = temp
End If
Next i
'now use the first k elements of the partially shuffled array:
For i = 1 To k
v(numbers(i)) = 1
Next i
sample = v
End Function
Used like: Range("A1:J1").Value = sample(10,7)
Using a bit of brute force, I think I've got a workable solution to the original version of the question which asked for random numbers between 0 and 1.
Cells A1 to A9:
=rand()
Cell A10:
=7-sum(A1:A9)
Now you have 10 numbers that add up to 7, but the last one is probably not in the range 0 to 1. To deal with that, just recalculate the sheet to generate new random numbers until that last value is within range. It takes about 25 recalculations to have a ~95% chance that one of them will be within range, so it could take a while. A little VBA can do that for you very quickly:
Sub rand7()
While Range("A10").Value > 1 Or Range("A10").Value < 0
ActiveSheet.Calculate
Wend
End Sub

Python - Negative numbers not adding, but positive numbers do

I am supposed to add up the rows and the grand total of all the numbers. I can add the grand total well, but I am unable to add the row that has negative numbers only. The following code adds up the positive numbers but do not add up the negative numbers correctly.
grandTotal = 0
sumRow = 0
for x in range(len(numbers)):
sumRow = (sumRow + x)
print(sumRow)
for x in range(len(numbers)):
for y in range(len(numbers[x])):
grandTotal = grandTotal + int(numbers[x][y])
print(grandTotal)
When the user input is:
1,1,-2 -1,-2,-3 1,1,1
My output is: 0
1
3
-3
instead of: 0
-6
3
-3
I know it has something to do with the first for loop, but I can't figure it out. When I try this:
grandTotal = 0
sumRow = 0
for x in range(len(numbers)):
sumRow = (sumRow + (numbers[x]))
print(sumRow)
for x in range(len(numbers)):
for y in range(len(numbers[x])):
grandTotal = grandTotal + int(numbers[x][y])
print(grandTotal)
I get the error message:
File "list.py", line 14, in
sumRow = (sumRow + (numbers[x]))
TypeError: unsupported operand type(s) for +: 'int' and 'list'
Why doesn't my code add up the negative numbers? Any help is greatly appreciated!
Where you say
sumRow = (sumRow + (numbers[x]))
To add integers you say 1+1, not (1+(1)) this would be adding to lists so you could change that.
From my understanding numbers is an array as well, so saying
numbers[x]
Will give you many numbers. What you want is the total for every row, and the total of all rows. Heres a program that does this. I am assuming that your program automatically gets numbers from the user input.
grandTotal = 0
for row in numbers:
#for each row we find total amount
rowTotl = 0
for value in row:
#for each column/ value we add tot the row total
rowTotl += value
print(rowTotl)
#add this row's value to the grandTotal before we move on
grandTotal += rowTotl
#After all adding we print grand total
print(grandTotal)
The reason your program doesn't add negative numbers, is really because the row totals are not adding numbers at all. They are just adding the indexes, rather than the value, so they don't work for positive number either. The grand total works because you are adding all the values properly, rather than adding the indexes. FYI,
for index in range(len(numbers)) :
does not give you the values, but rather : 0,1,2,3,4,5,6...(indexes) till the end of the range, to get the value numbers you would do
for value in numbers:

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