我有一个类似于以下内容的数据框:
X Y
1 3
1 7
1 9
2 12
2 4
2 8
3 11
3 3
3 5
我想创建一个新的变量Z,如果X = 1则为0.25,如果X = 2则为0.75,如果X = 3,则为0.95。
我尝试了下面的代码,它创建了一个变量Z然后遍历X,检查X是否是某个值,然后将Z设置为相应的正确值。例如:
data$Z <- 0
for (i in 1:length(data$X)){
if (data$X[i]==1) {data$Z <- 0.25)
if (data$X[i]==2) {data$Z <- 0.50)
if (data$X[i]==2) {data$Z <- 0.95)
}
问题是由于某种原因,条件触发器在此代码中没有被触发。如果我只使用第一个if语句运行它,那么Z的所有都设置为0.25。只有前两个,它们都是0.50等等。
有关正在发生的事情的任何线索?
答案 0 :(得分:4)
请使用ifelse
,因为它是矢量化的:
transform(dat, Z=ifelse(X==1,0.25,ifelse(X==2,0.75,0.95)))
X Y Z
1 1 3 0.25
2 1 7 0.25
3 1 9 0.25
4 2 12 0.75
5 2 4 0.75
6 2 8 0.75
7 3 11 0.95
8 3 3 0.95
9 3 5 0.95
PS:这里我假设X只取3个值。
修改强>
我喜欢使用sql案例进行此类操作。您可以清楚地了解业务逻辑,它作为矢量化版本(直觉)很快
library(sqldf)
dat$newX <- sqldf('SELECT CASE X
WHEN 1 THEN 0.25
WHEN 2 THEN 0.5
ELSE 0.95
END AS newX
FROM dat ')
答案 1 :(得分:4)
在这个简单的例子中,最简单的方法是使用子集:
data$Z <- 0.25
data$Z[data$X==2] <- 0.50
data$Z[data$X==3] <- 0.95
不需要任何循环或if / else语句。
答案 2 :(得分:4)
到目前为止,所有这些答案都假设您只有3个值(这是正确的,没有理由不这样做)。
但是,假设您的值可能超过3个,那么在这种情况下可以使用merge
:
# assuming this is your data (dummy)
set.seed(45)
df <- data.frame(x=rep(1:5, each=5), y=sample(25))
在这里,您有x
的五个唯一值。您可以使用要为X的每个值生成附加列的值创建data.frame
:
# here for each unique x, there is a value (just for example, randomly generated)
# equivalent to 0.25, 0.5 and 0.95 in your case
key <- data.frame(x=1:5, val=runif(5))
现在,您可以将merge
用作:
merge(df, key, by="x", all=T)
答案 3 :(得分:3)
您需要将Z设置为您希望在相同索引的值,其中x符合这些条件,因此:
data$Z <- 0
for (i in 1:length(data$X)){
if (data$X[i]==1) {data$Z[i] <- 0.25)
if (data$X[i]==2) {data$Z[i] <- 0.50)
if (data$X[i]==3) {data$Z[i] <- 0.95)
}
答案 4 :(得分:3)
它仅适用于一个ifelse
命令:
transform(dat, Z = ifelse(X == 3, 0.95, 0.25 + 0.5 * (X - 1)))
X Y Z
1 1 3 0.25
2 1 7 0.25
3 1 9 0.25
4 2 12 0.75
5 2 4 0.75
6 2 8 0.75
7 3 11 0.95
8 3 3 0.95
9 3 5 0.95
它甚至可以在没有任何ifelse
的情况下工作(感谢数学):
transform(dat, Z = 0.25 + round(0.50 * (X - 1) ^ .48, 2))
X Y Z
1 1 3 0.25
2 1 7 0.25
3 1 9 0.25
4 2 12 0.75
5 2 4 0.75
6 2 8 0.75
7 3 11 0.95
8 3 3 0.95
9 3 5 0.95