thank you to all who responded to my question, too many
of you to list individually...as this summary shows,
there are many ways to 'skin a cat'! thanks too, to the
several people who reminded me that it's ok to ask
seemingly simple questions
(as one put it, they are so much easier to answer!).
ORIGINAL QUESTION
} Subject: [S] simple?question
}
} hello all!
}
} i am trying to do something that seems incredibly simple, but
} since i am new to splus, i'm having difficulty.
}
} i have a vector of numbers, ranging from 1 to 7. i want to
} create a sum of
} this vector based on a set of contingencies...for every
} instance of 1 through
} 3, add 0, for every instance of 4 or 5 add 1, for all values
} greater than 5 add 2...
}
} so, i thought i'd use an if statement: (x in this case is the vector)
} test_if(x<5)0 if(x=5)1,else 2
}
} but i get an error message that i'm using 'if' illegally...
}
} now if this vector were small, or if i didn't have to do it
} over and over again, i'd just do it by hand, but neither case is true!
From: "CHASALOW, SCOTT [AG/2170]" <SCOTT.CHASALOW@cereon.com>
If I understand your question correctly, I would suggest
something like this:
y <- rep(0, length(x))
y[x == 4 | x == 5] <- 1
y[x > 5] <- 2
x + y
Such a vectorized computation very often is the way to go in Splus.
Here, the first three lines construct a vector y, parallel to x,
with 0, 1, or 2 in the proper places, and then we simply add the
two vectors x and y in one step.
Your attempt doesn't work because if() expects a single logical
value, while (x < 5) returns a logical vector of length length(x).
Also, you have illegal syntax. Something like you tried:
if (x < 5) x + 0 else if (x == 4 || x == 5) x + 1 else x + 2
would work only if length(x) == 1. Note that you need to use
"==" for comparisons, not "="; all the if's in a sequence need
to be separated by "else"; and no comma's allowed outside of
argument lists.
Another possibility, more similar to what you tried than is
my first suggestion, might be:
x <- ifelse(x > 5, x + 2, x)
x <- ifelse(x == 4 | x == 5, x + 1, x)
Here you need to be a bit more careful though; the order in which
you execute these two statements is crucial. If you did them
the other way around, all the 5's in x would become first 6 and
then 8.
From: Matt Calder <calder@phz.com>
Laura, I'm sure you'll get a lot of responses, but here's another. Let,
x <- c(2,4,1,4,6,4,3,7,6,4,1,2,4)
Now let,
between <- function(a, b) {return((x >= a) & (x <= b))}
y <- 0 * between(1,3) + 1 * between(4,5) + 2 * between(6,7)
So that y contains the coded values which you can sum or whatever. The trick
here is that T (true) is equal to 1, and F (false) is equal to 0.
From: "Alan M. Gross" <amg@research.telcordia.com>
try something like
y <- rep(2, along=x)
y[x <=3 ] <- 0
y[x == 4 | x == 5 ] <- 1
sum(y)
From: "Chuck Thayer" <cthayer@nic.com>
Hi, Laura
I'm not sure that I understand exactly what you are trying to do, but let me
take a stab at it. If I had a vector x defined below, I'd be apt to use the
S-Plus function that looks like: "ifelse( {condition}, if-value,
else-value)"
The commands below are intended to: 1) define a vector "x" with suitable
values, then 2) print it out, just to verify that I got what I wanted, 3)
define the component by component addends that I think you're looking for,
and finally, 4) add them up. The blank lines are for readability.
[Editorial note: I wrote this explanation in a somewhat pedantic tone in
order to be as clear as possible.]
Please note that I added a couple of error-checking terms that will throw
errors if your data is out of bounds. You would not need those checks for
values outside of your range if you are sure that your data is clean. The
first two "ifelse" terms will do what you want. There are more elegant
solutions, but you will get those from others.
Possible Solution:
[The initial ">" represents the command line prompt from S-Plus 4.5 for Win
95/NT.]
> x _ c(1,2,3,4,5,6,7,1,2,3,4,5,6,7,1)
> x
[1] 1 2 3 4 5 6 7 1 2 3 4 5 6 7 1
> ifelse(x>3,1,0) + ifelse(x>5,1,0) + ifelse(x>7,NA,0) + ifelse(x<1,NA,0)
[1] 0 0 0 1 1 2 2 0 0 0 1 1 2 2 0
> sum(ifelse(x>3,1,0) + ifelse(x>5,1,0) + ifelse(x>7,NA,0) +
ifelse(x<1,NA,0))
[1] 12
From: Dave Krantz <dhk@paradox.psych.columbia.edu>
Starting in the spirit of "test" statements of the sort you used,
the particular problem you raise can be solved by the expression:
ifelse(x < 5, x, ifelse(x==5, x+1, x+2))
That sort of nesting of ifelse() calls is not very pretty, however,
and gets less and less so as the problem gets more complicated.
Another, more easily generalized and transparently readable approach
would be:
x + (x==5)*1 + (x > 5)*2
This introduces two "dummy" variables, x==5 and x > 5, and uses
them as multipliers for the values to be added to x.
Even this can be annoying if you have many different ranges that
you need to define. In that case, here is another approach:
y <- cut(x, breaks=c(0, 4.5, 5.5, 8))
A <- c(0,1,2)
x + A[y]
This creates a categorical variable y that takes the values 1, 2, 3
accordingly as x satisfies one condition or another. The vector
A simply collects together the values that will be added to x,
depending on what condition is satisfied. Finally, the expression
A[y] selects the first, second, or third element of A, depending
on the coded category represented by each element of y. This
use of the [ ] function is perhaps the single most powerful and
useful feature of Splus, and it is one that is usually neglected
by people moving over from other languages that do not have
that sort of power.
From: Renaud Lancelot <lancelot@telecomplus.sn>
If I correctly understood what you want, ifelse() should do what you need:
> x <- floor(runif(25, 1, 8))
> X <- ifelse(x < 5, x, ifelse(x == 5, x + 1, x + 2))
> data.frame(x, X)
x X
1 3 3
2 4 4
3 7 9
4 3 3
5 1 1
6 2 2
7 7 9
8 4 4
9 7 9
10 6 8
11 2 2
12 5 6
13 5 6
14 5 6
15 3 3
16 1 1
17 2 2
18 3 3
19 5 6
20 1 1
21 4 4
22 3 3
23 5 6
24 2 2
25 4 4
From: "Charles C. Berry" <cberry@tajo.ucsd.edu>
you want ifelse()
but cut() will also work
> cut(1:7,c(0,3.5,5.5,7.5))
[1] 1 1 1 2 2 3 3
attr(, "levels"):
[1] "0.0+ thru 3.5" "3.5+ thru 5.5" "5.5+ thru 7.5"
> sum(cut(1:7,c(0,3.5,5.5,7.5))-1)
[1] 6
From: Franz Mueter <mueter@ims.alaska.edu>
Here is one relatively simple way to accomplish what you need using cut with
appropriate breakpoints to assign elements of the vector to three groups,
coded 1 through 3. Subtracting 1 will give you a vector with 0s, 1s, and 2s in
the appropriate places:
# create vector of numbers, ranging from 1 to 7:
> x <- sample(1:7,100,replace=T)
recode the vector:
> cut(x,breaks=c(0,3,5,7))-1
[1] 0 0 0 2 2 1 1 2 0 2 1 0 1 0 0 2 0 2 1 1 2 0 1 0 2 0 0 1 0 2 2 0 2 0 2 1 1
[38] 1 0 2 2 0 0 0 0 1 2 2 2 0 1 0 0 2 0 0 1 0 2 0 0 1 0 0 1 2 1 0 0 1 2 2 1 2
[75] 0 1 0 2 2 0 2 1 0 0 0 1 1 0 0 1 0 0 0 0 1 2 0 1 2 0
> sum(cut(x,breaks=c(0,3,5,7))-1)
[1] 82
From: Todd.Taylor@pnl.gov (Z. Todd Taylor)
Read up on the 'ifelse' function. It does element-by-element if-else
replacements. e.g., to add 1 to everything greater than 3:
new.x <- ifelse(x <= 3, x, x+1)
From: Bill Dunlap <bill@statsci.com>
You get a syntax error because you must use 'else' before the 2nd
clause of an if statement. E.g.,
if (x < 5) 0 else if (x==5) 1 else 2
Also note that == is used to test equality. = is used to label
arguments to functions and <- is used for assignments.
However, 'if' won't do what you want (at least it won't do it well) --
you may want the vectorized ifelse() function. Try
coded.x <- ifelse(x<=3, 0, ifelse(x<=5, 1, 2))
sum(coded.x)
From: Don MacQueen <macq@llnl.gov>
If I understand what you want, try this:
sum(
0*(x <= 3),
1*(x == 4 | x == 5),
2*(x >= 6)
)
And there are surely some more clever ways, but this should work.
From: Stephen Kaluzny <spk@statsci.com>
Try using the ifelse function that works on each element of the vector.
For your problem:
ifelse(x>3,ifelse(x>5,x+2,x+1),x)
From: Valerie Ventura <vventura@stat.cmu.edu>
0 * sum(x <= 3) + 1 * sum( (x >= 4) & (x <= 5) ) + etc ...
-----------------------------------------------------------------------
This message was distributed by s-news@wubios.wustl.edu. To unsubscribe
send e-mail to s-news-request@wubios.wustl.edu with the BODY of the
message: unsubscribe s-news
|