중첩 된 ifelse 문
아직 SAS 코드를 R로 변환하는 방법을 배우는 중이며 경고를받습니다. 내가 어디에서 실수하고 있는지 이해해야합니다. 제가하고 싶은 것은 본토, 해외, 외국인의 3 가지 인구 상태를 요약하고 구분하는 변수를 만드는 것입니다. 2 개의 변수가있는 데이터베이스가 있습니다.
- id 국적 :
idnat
(프랑스어, 외국인),
경우는 idnat
다음 프랑스어입니다 :
- id 출생지 :
idbp
(본토, 식민지, 해외)
정보를 다음 idnat
과 idbp
같은 새 변수로 요약하고 싶습니다 idnat2
.
- 지위 : k (본토, 해외, 외국인)
이러한 모든 변수는 "문자 유형"을 사용합니다.
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보다 크므로 첫 번째 대괄호 사이의 내용 만 고려됩니다. 미안하지만이 길이가 여기와 무슨 관련이 있는지 모르겠어요? 내가 어디에서 틀렸는 지 아는 사람 있나요?
스프레드 시트 응용 프로그램을 사용하는 경우 if()
구문 이있는 기본 함수 가 있습니다.
if(<condition>, <yes>, <no>)
구문은 ifelse()
R에서 정확히 동일합니다 .
ifelse(<condition>, <yes>, <no>)
if()
스프레드 시트 응용 프로그램 의 유일한 차이점 은 R ifelse()
이 벡터화 된다는 것 입니다 (벡터를 입력으로 취하고 출력에 벡터를 반환). a> b 인 경우 비교하고 예인 경우 1을 반환하고 그렇지 않은 경우 0을 반환하려는 예에 대해 스프레드 시트 응용 프로그램과 R의 다음 수식 비교를 고려하십시오.
스프레드 시트에서 :
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 0
ifelse()
여러 가지 방법으로 중첩 될 수 있습니다.
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")
)
무엇입니까 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)
SQL에 익숙하다면 package 에서 CASE
statement 를 사용할 수도 있습니다 .sqldf
다음과 같이 시도하십시오.
# 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
접근 방식은 더 효율적이고 일반적으로 더 적은 코드를 포함합니다.
데이터 세트에 많은 행이 포함되어있는 경우 data.table
중첩 대신을 사용하여 조회 테이블과 조인하는 것이 더 효율적일 수 있습니다 ifelse()
.
아래 룩업 테이블 제공
lookup
idnat 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
및 idnat2
없이 벡터 를 만들 수 있습니다 .if
ifelse
이 함수 replace
는 모든 항목을 다음 "colony"
으로 바꾸는 데 사용할 수 있습니다 "overseas"
.
idnat2 <- replace(idbp, idbp == "colony", "overseas")
dplyr 및 sqldf 패키지와 함께 SQL CASE 문 사용 :
데이터
df <-structure(list(idnat = structure(c(2L, 2L, 2L, 1L), .Label = c("foreign",
"french"), class = "factor"), idbp = structure(c(3L, 1L, 4L,
2L), .Label = c("colony", "foreign", "mainland", "overseas"), class = "factor")), .Names = c("idnat",
"idbp"), class = "data.frame", row.names = c(NA, -4L))
sqldf
library(sqldf)
sqldf("SELECT idnat, idbp,
CASE
WHEN idbp IN ('colony', 'overseas') THEN 'overseas'
ELSE idbp
END AS idnat2
FROM df")
dplyr
library(dplyr)
df %>%
mutate(idnat2 = case_when(.$idbp == 'mainland' ~ "mainland",
.$idbp %in% c("colony", "overseas") ~ "overseas",
TRUE ~ "foreign"))
산출
idnat idbp idnat2
1 french mainland mainland
2 french colony overseas
3 french overseas overseas
4 foreign foreign foreign
data.table의 솔루션은 다음과 같습니다.
DT[, idnat2 := ifelse(idbp %in% "foreign", "foreign",
ifelse(idbp %in% c("colony", "overseas"), "overseas", "mainland" ))]
는 ifelse
벡터화되어있다. 는 if-else
없습니다. 여기서 DT는 다음과 같습니다.
idnat idbp
1 french mainland
2 french colony
3 french overseas
4 foreign foreign
이것은 다음을 제공합니다.
idnat idbp idnat2
1: french mainland mainland
2: french colony overseas
3: french overseas overseas
4: foreign foreign foreign
# Read in the data.
idnat=c("french","french","french","foreign")
idbp=c("mainland","colony","overseas","foreign")
# Initialize the new variable.
idnat2=as.character(vector())
# Logically evaluate "idnat" and "idbp" for each case, assigning the appropriate level to "idnat2".
for(i in 1:length(idnat)) {
if(idnat[i] == "french" & idbp[i] == "mainland") {
idnat2[i] = "mainland"
} else if (idnat[i] == "french" & (idbp[i] == "colony" | idbp[i] == "overseas")) {
idnat2[i] = "overseas"
} else {
idnat2[i] = "foreign"
}
}
# Create a data frame with the two old variables and the new variable.
data.frame(idnat,idbp,idnat2)
파티에 너무 늦게 참여해서 죄송합니다. 여기에 쉬운 해결책이 있습니다.
#building up your initial table
idnat <- c(1,1,1,2) #1 is french, 2 is foreign
idbp <- c(1,2,3,4) #1 is mainland, 2 is colony, 3 is overseas, 4 is foreign
t <- cbind(idnat, idbp)
#the last column will be a vector of row length = row length of your matrix
idnat2 <- vector()
#.. and we will populate that vector with a cursor
for(i in 1:length(idnat))
#*check that we selected the cursor to for the length of one of the vectors*
{
if (t[i,1] == 2) #*this says: if idnat = foreign, then it's foreign*
{
idnat2[i] <- 3 #3 is foreign
}
else if (t[i,2] == 1) #*this says: if not foreign and idbp = mainland then it's mainland*
{
idnat2[i] <- 2 # 2 is mainland
}
else #*this says: anything else will be classified as colony or overseas*
{
idnat2[i] <- 1 # 1 is colony or overseas
}
}
cbind(t,idnat2)
참조 URL : https://stackoverflow.com/questions/18012222/nested-ifelse-statement
'programing' 카테고리의 다른 글
Haskell의 의존성 주입 : 관용적으로 작업 해결 (0) | 2021.01.17 |
---|---|
인증서의 공개 키를 .pem 형식으로 저장하는 방법 (0) | 2021.01.17 |
사용자의 이메일 주소를 얻기위한 Google OAuth API? (0) | 2021.01.17 |
Bootstrap-select-변경시 이벤트를 발생시키는 방법 (0) | 2021.01.17 |
SSH -X“경고 : 신뢰할 수없는 X11 전달 설정 실패 : xauth 키 데이터가 생성되지 않음” (0) | 2021.01.17 |