我仍在学习如何将SAS代码转换为R,并收到警告。我需要弄清楚我在哪里犯错误。我想要做的是创建一个变量来总结和区分一个人口的三个状态:大陆,海外,外国人。我有一个包含两个变量的数据库:
idnat (法语、外国人)如果idnat是法语,那么:
idbp (内地、殖民地、海外)我想将来自idnat和idbp的信息归纳为一个名为idnat2的新变量
所有这些变量都使用“字符类型”。
预期结果在idnat2栏中:
idnat idbp idnat2
1 french mainland mainland
2 french colony overseas
3 french overseas overseas
4 foreign foreign foreign下面是我想在R中翻译的SAS代码:
if idnat = "french" then do;
if idbp in ("overseas","colony") then idnat2 = "overseas";
else idnat2 = "mainland";
end;
else idnat2 = "foreigner";
run;以下是我在R中的尝试:
if(idnat=="french"){
idnat2 <- "mainland"
} else if(idbp=="overseas"|idbp=="colony"){
idnat2 <- "overseas"
} else {
idnat2 <- "foreigner"
}我收到这样的警告:
Warning message:
In if (idnat=="french") { :
the condition has length > 1 and only the first element will be used有人建议我使用“嵌套ifelse”来代替它的简单性,但会收到更多警告:
idnat2 <- ifelse (idnat=="french", "mainland",
ifelse (idbp=="overseas"|idbp=="colony", "overseas")
)
else (idnat2 <- "foreigner")根据警告消息,长度大于1,因此将只考虑第一个括号之间的内容。对不起,我不明白这个长度和这里有什么关系?有人知道我哪里错了吗?
发布于 2013-08-02 12:27:37
如果您正在使用任何电子表格应用程序,则有一个具有语法的基本函数if():
if(<condition>, <yes>, <no>)在R中,ifelse()的语法完全相同:
ifelse(<condition>, <yes>, <no>)在电子表格应用程序中,与if()的唯一区别是R ifelse()是矢量化的(将向量作为输入,在输出时返回向量)。考虑下面对电子表格应用程序中公式和R中公式的比较,例如,如果a>b,则返回1,如果不是,则返回0。
在电子表格中:
A B C
1 3 1 =if(A1 > B1, 1, 0)
2 2 2 =if(A2 > B2, 1, 0)
3 1 3 =if(A3 > B3, 1, 0)在R:
> a <- 3:1; b <- 1:3
> ifelse(a > b, 1, 0)
[1] 1 0 0ifelse()可以以多种方式嵌套:
ifelse(<condition>, <yes>, ifelse(<condition>, <yes>, <no>))
ifelse(<condition>, ifelse(<condition>, <yes>, <no>), <no>)
ifelse(<condition>,
ifelse(<condition>, <yes>, <no>),
ifelse(<condition>, <yes>, <no>)
)
ifelse(<condition>, <yes>,
ifelse(<condition>, <yes>,
ifelse(<condition>, <yes>, <no>)
)
)要计算列idnat2,可以:
df <- read.table(header=TRUE, text="
idnat idbp idnat2
french mainland mainland
french colony overseas
french overseas overseas
foreign foreign foreign"
)
with(df,
ifelse(idnat=="french",
ifelse(idbp %in% c("overseas","colony"),"overseas","mainland"),"foreign")
)R文件
the condition has length > 1 and only the first element will be used是什么?让我们看看:
> # What is first condition really testing?
> with(df, idnat=="french")
[1] TRUE TRUE TRUE FALSE
> # This is result of vectorized function - equality of all elements in idnat and
> # string "french" is tested.
> # Vector of logical values is returned (has the same length as idnat)
> df$idnat2 <- with(df,
+ if(idnat=="french"){
+ idnat2 <- "xxx"
+ }
+ )
Warning message:
In if (idnat == "french") { :
the condition has length > 1 and only the first element will be used
> # Note that the first element of comparison is TRUE and that's whay we get:
> df
idnat idbp idnat2
1 french mainland xxx
2 french colony xxx
3 french overseas xxx
4 foreign foreign xxx
> # There is really logic in it, you have to get used to it我还能用if()吗?是的,你可以,但语法并不那么酷:)
test <- function(x) {
if(x=="french") {
"french"
} else{
"not really french"
}
}
apply(array(df[["idnat"]]),MARGIN=1, FUN=test)发布于 2013-08-02 08:47:40
尝试如下所示:
# some sample data
idnat <- sample(c("french","foreigner"),100,TRUE)
idbp <- rep(NA,100)
idbp[idnat=="french"] <- sample(c("mainland","overseas","colony"),sum(idnat=="french"),TRUE)
# recoding
out <- ifelse(idnat=="french" & !idbp %in% c("overseas","colony"), "mainland",
ifelse(idbp %in% c("overseas","colony"),"overseas",
"foreigner"))
cbind(idnat,idbp,out) # check result您的困惑来自SAS和R如何处理if-else结构。在R中,if和else不是向量化的,这意味着它们检查单个条件是否为真(即if("french"=="french")工作),并且不能处理多个逻辑(即if(c("french","foreigner")=="french")不工作),并且R会给出您收到的警告。
相反,ifelse是向量化的,因此它可以接受向量(也称为输入变量),并测试每个元素的逻辑条件,就像您在SAS中所习惯的那样。解决这个问题的另一种方法是使用if和else语句构建一个循环(就像您在这里开始做的那样),但是矢量化的ifelse方法将更高效,并且通常只涉及较少的代码。
发布于 2017-09-29 07:47:25
如果数据集包含许多行,则使用data.table而不是嵌套的ifelse()连接查找表可能更有效。
提供了下面的查找表
lookupidnat idbp idnat2 1: french mainland mainland 2: french colony overseas 3: french overseas overseas 4: foreign foreign foreign
和一个样本数据集
library(data.table)
n_row <- 10L
set.seed(1L)
DT <- data.table(idnat = "french",
idbp = sample(c("mainland", "colony", "overseas", "foreign"), n_row, replace = TRUE))
DT[idbp == "foreign", idnat := "foreign"][]idnat idbp 1: french colony 2: french colony 3: french overseas 4: foreign foreign 5: french mainland 6: foreign foreign 7: foreign foreign 8: french overseas 9: french overseas 10: french mainland
然后我们可以在加入时进行更新。
DT[lookup, on = .(idnat, idbp), idnat2 := i.idnat2][]idnat idbp idnat2 1: french colony overseas 2: french colony overseas 3: french overseas overseas 4: foreign foreign foreign 5: french mainland mainland 6: foreign foreign foreign 7: foreign foreign foreign 8: french overseas overseas 9: french overseas overseas 10: french mainland mainland
https://stackoverflow.com/questions/18012222
复制相似问题