I did a little research and gave my respondents the option "other" where they could specify where they're from if not from those categories that I gave them as options. This "other" category has been coded as category "6". But some people didn't read the existing categories well and wrote essentially what was given to them as an option. How can I change this in the dataset? So change a specific value "6" to "2" while using SPSS syntax? I tried looking everywhere but I haven't been able to find an answer :(
if your variable is var1; you can write and run in a syntax window:
recode var1 (6=2).
execute.
This will replace all 6 in var1 with a 2.
You can also create a new var2, hence making sure you are not overwriting your original var1:
recode var1 (6=2) (else=copy) into var2.
execute.
You might want to do this only for respondents you have identified as not having read all the answers correctly. Then you might want to create an additional variable:
misread
with values 1 if you want to change 6 into 2, and 0 if you want to keep 6.
Your code is, then:
do if (misread = 1).
recode var1 (6=2) (else=copy) into var2.
end if.
Related
I am working with data from a multiple choice survey question. Survey respondents were able to select options A, B, C and/or D. The data file simply lists the response(s) they chose, with no spaces, commas or semicolons in between. For example, the data for a respondent who selected options A and C would simply be "AC"; the data for a respondent who selected options A, B, C and D would be "ABCD".
I need to create 4 new variables that indicate whether the respondent selected each of the 4 choices (i.e., if they didn't select A then A = 0; if they did select A then A = 1, and so on). How do I do this with my string data, given that there are no spaces or commas between the responses? I would greatly appreciate your help!
The OP correctly hinted at the answer in his comment, but for the sake of clarity, and in the spirit of Stack Overflow, here is the full answer:
Assuming multi_answer is the string variable holding the survey answer:
DO REPEAT answers="A" "B" "C" D"
/vars=var1 to var4.
COMPUTE vars=0.
if CHAR.INDEX(multi_answer,answers)<>0 vars=1.
END REPEAT.
EXECUTE.
Edit:
As per eli-k's comment, a more synthetic way is to use this inside the DO REPEAT END REPEAT structure:
compute vars=char.index(multi_answer,answers)>0.
so you don't need the compute vars=0.
End of Edit.
Both codes will create 4 variables (var1 var2 var3 var4) with values of 0 or 1, as described in the question.
IBM SPSS Official help on the string functions (including CHAR.INDEX function) : https://www.ibm.com/support/knowledgecenter/pl/SSLVMB_23.0.0/spss/base/syn_transformation_expressions_string_functions.html
Also a possible duplicate of this :):
SPSS: how to find text in text?
I have a question concerning the use of presentation variables:
1) What's the correct syntax for filtering on a presentation variable is used? You allow a user to select multiple values in a filter eg. A and B. If you use the syntax = '#{PV}{%}' it will result in this sql: = 'A, B' which of course won't exist in the data. I'd like to have this result: in ('A', 'B').
I've already found this syntax: (#{PV}['#']) which gives the correct sql, only thing here is that this doesn't work when you have a dashboard prompt where you allow 'all column values'. When no value is passed to this presentation variable, the analysis throws an error. I have no idea how to put a default value in this one. Any ideas on this?
2) Is there any configuration or setting where you can push obi to use a presentation variable in stead of using the 'normal' way of filtering as shown here:
The obi way is that it changes the relation to the relation in the prompt (if the prompt says 'is greater than' it will change here as well, even though you've put here 'is equal to'), but it will also use a value for this dimension if there's ever been a value for this, rather than listening to the value in the presentation variable of the dashboard prompt. I know that you can translate this to SQL but that's not the way to go for me. The behaviour I'd like is (in this exact order):
- when there is a value in the presentation variable in the dashboard prompt, take this.
- when there is a value for this role of the dimension, take that.
The reason why is because we have this dimension 'Afdeling' which can take up many roles but our customer asked for the roles to be hidden from the end user. This means that even though you switch roles, the end user always sees 'Afdeling' and couldn't care less in which role it is looking at its 'Afdeling'. They can switch between different dashboard pages and if I'd put on top of the page the dashboardprompt of the 'Afdeling' in the role it needed to be, the value won't pass through when switching pages to another dashboardprompt of another role. That way the end user would know something was up. So the value needs to pass through the prompt on each page, no matter what the role of that dimension.
After a bit of googling I've found the answer to question 1 myself. Thanks to this website https://www.obieetips.com/2014/05/obiee-11g-using-multiple-value-for.html I now know that the correct syntax is (#{pv_region}['#']{'West '})
I have strings in a namelist, that correspond to variables as well as field names in the application.
The function should read strings from namelist, add an 'f' to get field_names, and then put variable values in corresponding fields.
I tried following code, that does not give any error, but also does not work:
namelist: ["var1" "var2"]
var1: 5
var2: 10
process: [
repeat i length? namelist [
(to-set-path compose rejoin [namelist/:i "f/text"] (to-word namelist/:i))
]
]
lay: layout [
text "Values to appear here: "
var1f: field "a"
var2f: field "b"
button "Click" [do process]
]
view lay
As a general point: it is easy to turn strings into WORD!s (e.g. to-word "foo"). However, it can be tough to magically make that WORD! reference be bound to "the variable you meant". The wily reasons for this have to do with the fact that there is no scope. See:
Is there a overall explanation about definitional scoping in Rebol and Red
So what you are trying to do is going to be a little dodgy regardless. There are better ways. But to try to avoid un-asking the question, I'll explain what's happening here and how to fix it in the style you were attempting.
corrected version is for instructional purposes only. please do this another way.
compose rejoin [namelist/:i "f/text"]
REJOIN is applied to blocks, and merges the contents, with a result type loosely based on the first element. (It's a questionable operation, but historically popular in Rebol code.)
Since namelist/:i is a string, your REJOIN will produce a string...and this string will wind up being passed to COMPOSE. But COMPOSE is meant to be applied to BLOCK!s...and searches for parenthesized groups inside of it, evaluating them while leaving the rest of the code alone. It's a kind of templating system for blocks, with no effect on other kinds of input...so you'll get the same string out.
TO-SET-PATH is thus being fed a STRING! (e.g. "var1f/text"). I didn't even know that path conversion accepted strings. I find the behavior of this operation to be puzzling, because it apparently LOADs the string and then makes it the singular element of a length 1 SET-PATH!.
>> p: to-set-path "foo/bar"
== foo/bar: ;-- huh? really, did that work?
>> type? p
== set-path! ;-- ok, good, I guess.
>> length? p
== 1 ;-- wait, what?
>> type? first p
== path! ;-- a PATH! inside a SET-PATH!...?
>> length? first p
== 2
>> type? first first p
== word!
>> foo: 10
>> get first first p
== 10 ;-- well, at least it's bound
That's not making the kind of SET-PATH! you want; you want a SET-PATH! with 2 WORD! elements. Converting a BLOCK! to a SET-PATH! would be a way of doing this.
to-set-path compose [(load rejoin [namelist/:i "f"]) text]
Now we see COMPOSE being used correctly, where it will run the evaluation inside the parentheses and leave the text word alone. This produces a block with 2 elements in it, which is easily converted to a SET-PATH!. I'm using LOAD instead of TO-WORD to take care of some of the "magic" of connecting to an actual variable that plain word conversion would not do. But it's just a workaround--not a sure thing, and won't always be the answer to the problem.
But producing a SET-PATH! doesn't mean it runs. If I say:
s: to-set-word "x"
probe type? s
No SET-WORD! is executed, it's merely generated. And in this case, stored in the variable s. But if I hadn't stored it in a variable, the evaluation product would have just been thrown out...the way 2 is simply thrown out if I write 1 + 1 print "hi". To execute the SET-PATH!, you need to put it in a context where it will be composed into source and evaluated.
(Note: Ren-C has a primitive called EVAL which can do this on the fly, e.g. eval (quote x:) 10 will assign 10 to x.)
But in Red you'll need to do something like this:
namelist: ["var1" "var2"]
var1: 5
var2: 10
process: [
repeat i length? namelist [
do probe compose [
(to-set-path compose [(load rejoin [namelist/:i "f"]) text])
to-string
(load namelist/:i)
]
]
]
lay: layout [
text "Values to appear here: "
var1f: field "a"
var2f: field "b"
button "Click" [do process]
]
view lay
Now your outer COMPOSE is building an 3-element block, where the first element will be a SET-PATH!, the second a WORD! that was literally left alone to convert your integer to a string, and the third a WORD! that will be evaluated to the relevant integer. The DO of that block will have the assignment effect.
I changed your to-word namelist/:i to load namelist/:i. Again, for the reason I mentioned...TO-WORD alone doesn't put on a "binding".
I left a PROBE in there so you could see what is built and executed:
[var1f/text: to-string var1]
[var2f/text: to-string var2]
PROBE is a very helpful tool, which outputs its argument but also passes it through. You can insert it at various points in your code to get a better understanding of what's going on.
(Note: If you're wondering why I don't suggest writing a narrow EVAL-2 helper operation that only works for SET-PATH!, it's because such a thing exists with a better name. It's called SET. Try set (quote x:) 10 then print x. In fact, variants of this is how you'd actually want to do things... obj: make object! [a: 10] then set (in obj 'a) 20 then print obj/a. As I said, there's a lot better ways to go about what you're doing, but I tried to stay focused on doing it the-way-you-were-trying.)
This doesn't directly answer your question, though seems to address the problem you're facing. It uses the face/extra field to associate the fields to your value list:
namelist: [var1 var2]
var1: 5
var2: 10
process: function [][
foreach face lay/pane [
if find namelist face/extra [
face/text: form get to word! face/extra
]
]
]
lay: layout [
text "Values to appear here: "
field "a" extra 'var1
field "b" extra 'var2
button "Click" [process]
]
view lay
The only wrinkles are: it applies get to the words as they are set in the View spec—they need to be within the same context as the values you're working on, and—you can't get a lit-word! so have to change it to word! before getting.
Another approach if you want to contain your values in a map:
values: #(foo: 5 bar: 10)
process: function [container [object!]][
foreach face container/pane [
if find values face/extra [
face/text: form select values face/extra
]
]
]
view [
text "Values to appear here: "
field "a" extra 'foo
field "b" extra 'bar
button "Click" [process face/parent]
]
Step 1: refactor
Here is your code reformatted and print (1) statements added:
namelist: ["var1" "var2"]
var1: 5
var2: 10
process: [
print "process: start" ; (1)
repeat i length? namelist [
(to-set-path compose rejoin [namelist/:i "f/text"] (to-word namelist/:i))
]
print "process: end" ; (1)
]
lay: layout [
text "Values to appear here: "
var1f: field "a"
var2f: field "b"
button "Click" [do process]
]
view lay
When I run this in the console and press "Click", it gives the following:
process: start
process: end
So I know at least the button works
Step 2: debug with print
Now I can focus, moving print inside the code block:
process: [
repeat i length? namelist [
print (
to-set-path compose rejoin [
namelist/:i "f/text"
] (to-word namelist/:i)
)
]
]
Almost immediately I can see what's wrong here :
var1 ; expecting `var1f` here
var2 ;
Step 3: we need to go deeper with probe
Aside
Now, before I proceed further, notice that this code doesn't access
anything inside the view block (because it doesn't work!).
But the nice thing here is you could ignore this and come back to it later.
What you need is a way to access var1f/text programmatically
Keeping that in mind, here is a better way to phrase this question:
Step 3a: how to dynamically create objects with different names and set values to them?
var1f/text: 5
(given the code in step 2)
Now, I reach a conundrum here. This would probably be best asked as a different, simpler question.
I decided to continue assuming you accomplished this (there's another answer too)
Note
The important thing to take home in this step is the datatype Red view uses and what you're working with is the same thing: red objects.
There is no difference (all are instances of a simple face object)
Step 4: you're done! Or are you?
So you're able to create the gui you want for your work and you're done!
Right?
But then you ask yourself, is this the best way to do it?
What if you want to add some more of this, or something else entirely?
You have read the official gui docs especially the part about view engine
You've looked at examples of vid and adding view face objects manually
You've looked at the repo on github for sample code and small apps
You've even tried the old, but stable rebol2
But you still don't get it? Don't despair, this is normal.
A lot of stuff have names that are conceptually similar to what you are familiar in other languages but are different in subtle ways which tends to make them really different.
In the end tho, a lot is simpler than you'd think but stranger(having deeper implications)
tl;dr
Separate your view code from the rest so it's easier to debug
Use print, probe and dump-face to debug
I am trying to assign multiple codes to existing variables. I am using the syntax below, but it will only assign the first code entered for that hosp.id.number.
Syntax example:
Do if (hosp.id.number=9037) or (hosp.id.number=1058) or (hosp.id.number=11256).
Compute role_EM_communication=10.
Else if (hosp.id.number=9037.
Compute role_EM_communication=11.
End if.
Execute.
hosp.id.number needs to be coded 10 and 11, but it will only code it at 10. Anyway to rephrase so that SPSS will accept 2 or more codes for a variable such as hosp.id.number?
Your role_EM_communication variable is a single variable, but from what you are saying, I think you need it to be a set (for the same record, it could take on more than just one code). So you need to create n variables named role_EM_communication_1 to role_EM_communication_n, where n is the maximum number of codes you estimate will be possible for one record.
For your example, it would translate like this:
create the 2 variables:
vector role_EM_communication_ (2, f2.0).
do the first recode:
if any(hosp.id.number,9037,1058,11256) role_EM_communication_1=10.
very important - execute the recode
exe.
check if the first variable has data, and populate the second variable if true:
if miss(role_EM_communication_1) and any(hosp.id.number,9037) role_EM_communication_1=11.
if ~miss(role_EM_communication_1) and any(hosp.id.number,9037) role_EM_communication_2=11.
exe.
I have three variables with the following values...
put 10 into var1
put 7 into var2
put 2 into var3
How to get the highest value? For this example, I want to return 10 and display that "10 is the highest number". How can I achieve this?
This is quite standard in any programming language.
put max(var1,var2,var3) into myMax