How to find a cell based on row and col criteria? - openoffice-calc

I have a table like this:
| a | b | c |
x | 1 | 8 | 6 |
y | 5 | 4 | 2 |
z | 7 | 3 | 5 |
What I want to do is finding a value based on the row and col titles, so for example if I have c&y, then it should return 2. What function(s) should I use to do this in OpenOffice Calc?
later:
I tried =INDEX(B38:K67;MATCH('c';B37:K37;0);MATCH('y';A38:A67;0)), but it writes invalid argument.

It turned out I wrote the arguments of INDEX in the wrong order. The =INDEX(B38:K67;MATCH('y';A38:A67;0);MATCH('c';B37:K37;0)) formula works properly. The second argument is the row number and not the col number.

Related

Conditional formatting on particular columns in Tableau

I have a sample dataset on which I want to perform conditional formatting. In the given sample of data, if values in column Item3>=Item1 then the corresponding records in Item3 should be highlighted in green else in red. Similarly, if values in column Item4>=Item2 then the corresponding records in Item4 should be highlighted in green else in red.
| Group | Item1 | Item2 | Item3 | Item4 |
|-------|-------|-------|-------|-------|
| A | 3 | 1 | 1 | 1 |
| B | 4 | 3 | 4 | 3 |
| C | 5 | 6 | 2 | 8 |
| D | 9 | 4 | 10 | 6 |
| E | 6 | 9 | 7 | 7 |
| F | 4 | 5 | 5 | 7 |
| G | 7 | 5 | 9 | 6 |
In the above example, rows 1 and 3 under Item3 column should be highlighted in red and rest of them in green while row 5 under Item4 column should be highlighted in red and rest in green.
I have tried creating a calculated field using if-else statement, but it highlights all the values. How can I achieve it for highlighting the cells in columns 'Item3' and 'Item4'?
One way to achieve this Viz is to have 3 sheets. First sheet is group, item1, and item 2. Second sheet is group and item3. Third Sheet is group and item4.
Create two calculated fields "3>1" and "4>2" and assign these as colors to second and third sheet respectively. Then make a dashboard with all three sheets floating, overlapping, adjusting which one is in front. I punted on titles.
Here's my result.
And here: https://public.tableau.com/app/profile/wade.schuette/viz/color-columns/Dashboard1?publish=yes

How to index match a condition set in a cell

I am trying to avoid having a multiple if formula by index matching a table instead, however what i need to match is the actual condition and a string.
Lookup table:
+---+------------------+-------------------+-------+
| | A | B | C |
+---+------------------+-------------------+-------+
| 1 | Current to Prior | Portfolio Comment | Error |
| 2 | =0 | "" | 1 |
| 3 | <>0 | "" | -1 |
| 4 | >0 | OK – Losses | 0 |
| 5 | <0 | OK – Losses | 1 |
| 6 | <0 | OK – New Sales | 0 |
| 7 | >0 | OK – New Sales | 1 |
+---+------------------+-------------------+-------+
Column A: Lookup Condition
Column B: Lookup string
Column C: Return value
Data example with correct hard coded output (column C):
+---+------------------+-------------------+-------+
| | A | B | C |
+---+------------------+-------------------+-------+
| 1 | Current to Prior | Portfolio comment | Error |
| 2 | 0 | | 1 |
| 3 | -100 | OK – Losses | 1 |
| 4 | 50 | | -1 |
| 5 | 200 | OK – Losses | 0 |
| 6 | 0 | | 1 |
| 7 | -400 | OK – New Sales | 0 |
| 8 | 0 | | 1 |
+---+------------------+-------------------+-------+
Column A: Data value
Column B: Data string
Column C: Output formula
I need a formula that matches the data value with the lookup condition, the data string with the lookup string and outputs the return value.
I know you weren't necessarily asking for a VBA solution, but myself (and many others) prefer using UDFs as, in my opinion, it makes reading formulas easier and cleaner - plus you can do without the helper cells.
We start off your UDF by creating a Select Case Statement. We could choose to use either the Numerical Value or String for the cases. I decided to go with the string.
Within each case, you will compare the numerical values provided to the lngCondition parameter, which will ultimately return the value to the function.
Since you didn't have any cases for when textual values could have a lngCondition = 0, I made it return a worksheet error code #VALUE, just as you'd expect from any other Excel formula. This is the reason for the UDF having a variant return type.
Public Function ReturnErrorCode(lngCondition As Long, strComment As String) As Variant
Select Case strComment
Case ""
If lngCondition = 0 Then
ReturnErrorCode = 1
Else
ReturnErrorCode = -1
End If
Case "OK - Losses"
If lngCondition > 0 Then
ReturnErrorCode = 0
ElseIf lngCondition < 0 Then
ReturnErrorCode = 1
Else
' Your conditions don't specify that 'OK - Losses'
' can have a 0 value
ReturnErrorCode = CVErr(xlErrValue)
End If
Case "OK - New Sales"
If lngCondition < 0 Then
ReturnErrorCode = 0
ElseIf lngCondition > 0 Then
ReturnErrorCode = 1
Else
' Your conditions don't specify that 'OK - New Sales'
' can have a 0 value
ReturnErrorCode = CVErr(xlErrValue)
End If
Case Else
ReturnErrorCode = CVErr(xlErrValue)
End Select
End Function
You would then use this formula in the worksheet as such:
=ReturnErrorCode(A1, B1)
Great! But I have no knowledge of VBA and don't know how to add a UDF.
First, you need to open the VBA Editor. You can do this by simultaneously pressing Alt + F11.
Next, you need to create a standard code module. In the VBE, click Insert then select Module (NOT Class module!).
Then copy the code above, and paste it into the new code module you just created.
Since you have now added VBA code to your workbook, you now need to save it as a macro-enabled workbook the next time you save.

Generate variable with odd and even labels

I have a variable num with values 1-10.
I would like to create a new variable type with values odd or even:
generate type = odd if inlist(num, 1,3,5,7,9)
Questions:
What is the cleanest way to also label even numbers?
Could I use a negation somewhere and keep the command all in one line?
The code you provide is not valid syntax:
clear
set obs 10
generate num = _n
generate type = odd if inlist(num, 1,3,5,7,9)
odd not found
r(111);
You could get what you want with:
generate type = "odd" if inlist(num, 1,3,5,7,9)
And you can do both at the same time using the cond() function:
generate type = cond(inlist(num, 1,3,5,7,9), "odd", "even")
However, having this variable as a string will be of limited value for later use.
You could subsequently use the encode command to create a new variable of numeric type:
encode type, generate(type2)
list
+--------------------+
| num type type2 |
|--------------------|
1. | 1 odd odd |
2. | 2 even even |
3. | 3 odd odd |
4. | 4 even even |
5. | 5 odd odd |
|--------------------|
6. | 6 even even |
7. | 7 odd odd |
8. | 8 even even |
9. | 9 odd odd |
10. | 10 even even |
+--------------------+
Although seemingly identical, type and type2 variables are indeed of a different type:
list, nolabel
+--------------------+
| num type type2 |
|--------------------|
1. | 1 odd 2 |
2. | 2 even 1 |
3. | 3 odd 2 |
4. | 4 even 1 |
5. | 5 odd 2 |
|--------------------|
6. | 6 even 1 |
7. | 7 odd 2 |
8. | 8 even 1 |
9. | 9 odd 2 |
10. | 10 even 1 |
+--------------------+
This is how you can do it with type being a numeric variable:
generate type = mod(num, 2)
list
+------------+
| num type |
|------------|
1. | 1 1 |
2. | 2 0 |
3. | 3 1 |
4. | 4 0 |
5. | 5 1 |
|------------|
6. | 6 0 |
7. | 7 1 |
8. | 8 0 |
9. | 9 1 |
10. | 10 0 |
+------------+
You then create the value label and attach it to the variable type:
label define numlab 0 "even" 1 "odd"
label values type numlab
list
+------------+
| num type |
|------------|
1. | 1 odd |
2. | 2 even |
3. | 3 odd |
4. | 4 even |
5. | 5 odd |
|------------|
6. | 6 even |
7. | 7 odd |
8. | 8 even |
9. | 9 odd |
10. | 10 even |
+------------+
If you only want the odd numbers labeled you can simply do:
label define numlab 1 "odd"
If you later change your mind and want to add a label for even numbers:
label define numlab 0 "even", add
When your command has been run, the value of type for the odd numbers is "odd" and the value for the even numbers is "", that is a missing string.
You could tag the even numbers using
replace type = "even" if type==""
I cannot think of a way to keep it all in one line, since you have to both generate the variable and fill in two different string values.
If you could use a numeric variable (I name it flag) as your type variable, you could try this:
gen flag = mod(num,2)
This will flag the odd numbers as 1 and the even numbers as 0. You could then create a label for the flag variable, if you need to display its values as "odd" and "even".

Weighted Cumulative Sum in Python

So I'm trying to figure out a good way of vectorizing a calculation and I'm a bit stuck.
| A | B (Calculation) | B (Value) |
|---|----------------------|-----------|
| 1 | | |
| 2 | | |
| 3 | | |
| 4 | =SUM(A1:A4)/4 | 2.5 |
| 5 | =(1/4)*A5 + (3/4)*B4 | 3.125 |
| 6 | =(1/4)*A6 + (3/4)*B5 | 3.84375 |
| 7 | =(1/4)*A7 + (3/4)*B6 | 4.6328125 |
I'm basically trying to replicate Wilder's Average True Range (without using TA-Lib). In the case of my simplified example, column A is the precomputed True Range.
Any ideas of how to do this without looping? Breaking down the equation it's effectively a weighted cumulative sum... but it's definitely not something that the existing pandas cumsum allows out of the box.
This is indeed an ewm problem. The issue is that the first 4 rows are crammed together into a single row... then ewm takes over
a = df.A.values
d1 = pd.DataFrame(dict(A=np.append(a[:4].mean(), a[4:])), df.index[3:])
d1.ewm(adjust=False, alpha=.25).mean()
A
3 2.500000
4 3.125000
5 3.843750
6 4.632812

Stata: Cumulative number of new observations

I would like to check if a value has appeared in some previous row of the same column.
At the end I would like to have a cumulative count of the number of distinct observations.
Is there any other solution than concenating all _n rows and using regular expressions? I'm getting there with concatenating the rows, but given the limit of 244 characters for string variables (in Stata <13), this is sometimes not applicable.
Here's what I'm doing right now:
gen tmp=x
replace tmp = tmp[_n-1]+ "," + tmp if _n > 1
gen cumu=0
replace cumu=1 if regexm(tmp[_n-1],x+"|"+x+",|"+","+x+",")==0
replace cumu= sum(cumu)
Example
+-----+
| x |
|-----|
1. | 12 |
2. | 32 |
3. | 12 |
4. | 43 |
5. | 43 |
6. | 3 |
7. | 4 |
8. | 3 |
9. | 3 |
10. | 3 |
+-----+
becomes
+-------------------------------+
| x | tmp |
|-----|--------------------------
1. | 12 | 12 |
2. | 32 | 12,32 |
3. | 12 | 12,32,12 |
4. | 43 | 3,32,12,43 |
5. | 43 | 3,32,12,43,43 |
6. | 3 | 3,32,12,43,43,3 |
7. | 4 | 3,32,12,43,43,3,4 |
8. | 3 | 3,32,12,43,43,3,4,3 |
9. | 3 | 3,32,12,43,43,3,4,3,3 |
10. | 3 | 3,32,12,43,43,3,4,3,3,3|
+--------------------------------+
and finally
+-----------+
| x | cumu|
|-----|------
1. | 12 | 1 |
2. | 32 | 2 |
3. | 12 | 2 |
4. | 43 | 3 |
5. | 43 | 3 |
6. | 3 | 4 |
7. | 4 | 5 |
8. | 3 | 5 |
9. | 3 | 5 |
10. | 3 | 5 |
+-----------+
Any ideas how to avoid the 'middle step' (for me that gets very important when having strings in x instead of numbers).
Thanks!
Regular expressions are great, but here as often elsewhere simple calculations suffice. With your sample data
. input x
x
1. 12
2. 32
3. 12
4. 43
5. 43
6. 3
7. 4
8. 3
9. 3
10. 3
11. end
end of do-file
you can identify first occurrences of each distinct value:
. gen long order = _n
. bysort x (order) : gen first = _n == 1
. sort order
. l
+--------------------+
| x order first |
|--------------------|
1. | 12 1 1 |
2. | 32 2 1 |
3. | 12 3 0 |
4. | 43 4 1 |
5. | 43 5 0 |
|--------------------|
6. | 3 6 1 |
7. | 4 7 1 |
8. | 3 8 0 |
9. | 3 9 0 |
10. | 3 10 0 |
+--------------------+
The number of distinct values seen so far is then just a cumulative sum of first using sum(). This works with string variables too. In fact this problem is one of several discussed within
http://www.stata-journal.com/sjpdf.html?articlenum=dm0042
which is accessible to all as a .pdf. search distinct would have pointed you to this article.
Becoming fluent with what you can do with by:, sort, _n and _N is an important skill in Stata. See also
http://www.stata-journal.com/sjpdf.html?articlenum=pr0004
for another article accessible to all.