ifelse ()가 Date 객체를 숫자 객체로 바꾸는 것을 방지하는 방법
ifelse()
날짜 벡터를 조작하는 함수 를 사용하고 있습니다 . 결과가 class Date
일 것으로 예상하고 numeric
대신 벡터 를 얻는 것에 놀랐습니다 . 예를 들면 다음과 같습니다.
dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04', '2011-01-05'))
dates <- ifelse(dates == '2011-01-01', dates - 1, dates)
str(dates)
전체 벡터에서 연산을 수행하면 Date
객체를 반환하기 때문에 이는 특히 놀라운 일 입니다.
dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04','2011-01-05'))
dates <- dates - 1
str(dates)
Date
벡터 에서 작동하려면 다른 함수를 사용해야합니까 ? 그렇다면 어떤 기능을 수행합니까? 그렇지 않은 경우 ifelse
입력과 동일한 유형의 벡터를 어떻게 강제 로 반환합니까?
에 대한 도움말 페이지 ifelse
는 이것이 버그가 아니라 기능이라는 것을 나타내지 만 여전히 놀라운 행동으로 밝혀진 것에 대한 설명을 찾기 위해 고심하고 있습니다.
data.table::fifelse
( data.table >= 1.12.3
) 또는을 사용할 수 있습니다 dplyr::if_else
.
data.table::fifelse
달리
ifelse
,fifelse
입력의 유형과 클래스를 유지합니다.
library(data.table)
dates <- fifelse(dates == '2011-01-01', dates - 1, dates)
str(dates)
# Date[1:5], format: "2010-12-31" "2011-01-02" "2011-01-03" "2011-01-04" "2011-01-05"
fifelse
벤치 마크를 포함한 에 대한 자세한 정보 는 개발 버전 1.12.3의 뉴스 항목 # 21을 참조하십시오 . 개발 버전의 설치는 여기를 참조 하십시오 .
dplyr::if_else
에서 dplyr 0.5.0
릴리스 노트 : "[ if_else
즉 엄격한 의미가 ifelse()
다음 true
과 false
. 인수는 같은 유형이어야합니다을이 덜 놀라운 반환 유형을 제공하고, 같은 S3 벡터를 보존 날짜 ".
library(dplyr)
dates <- if_else(dates == '2011-01-01', dates - 1, dates)
str(dates)
# Date[1:5], format: "2010-12-31" "2011-01-02" "2011-01-03" "2011-01-04" "2011-01-05"
이 문서화 된 관련 값 의 ifelse
:
동일한 길이 (기준 및 "속성들을 포함하는 벡터
class
와 같은")test
의 값과 데이터 값yes
또는no
. 답의 모드는 논리 값에서 강요되어 첫 번째로 얻은 값yes
과 그 후의 값을 수용no
합니다.
그 의미에 따라 삶의 질을 떨어 뜨리고 ifelse
날짜는 클래스를 잃고 모드 ( "숫자") 만 복원됩니다. 대신 이것을 시도하십시오 :
dates[dates == '2011-01-01'] <- dates[dates == '2011-01-01'] - 1
str(dates)
# Date[1:5], format: "2010-12-31" "2011-01-02" "2011-01-03" "2011-01-04" "2011-01-05"
당신은 만들 수 있습니다 safe.ifelse
:
safe.ifelse <- function(cond, yes, no){ class.y <- class(yes)
X <- ifelse(cond, yes, no)
class(X) <- class.y; return(X)}
safe.ifelse(dates == '2011-01-01', dates - 1, dates)
# [1] "2010-12-31" "2011-01-02" "2011-01-03" "2011-01-04" "2011-01-05"
나중에 메모 : Hadley가 if_else
데이터 형성 패키지의 magrittr / dplyr / tidyr 복합체에 내장되어 있음 을 알았습니다.
DWin의 설명이 돋보입니다. 나는 ifelse 문 다음에 수업을 강요 할 수 있다는 것을 깨닫기 전에 잠시 동안 이것을 피하고 싸웠다.
dates <- as.Date(c('2011-01-01','2011-01-02','2011-01-03','2011-01-04','2011-01-05'))
dates <- ifelse(dates=='2011-01-01',dates-1,dates)
str(dates)
class(dates)<- "Date"
str(dates)
처음에 이것은 나에게 약간의 "해킹"을 느꼈다. 그러나 이제는 ifelse ()에서 얻은 성능 수익을 지불하는 작은 가격으로 생각합니다. 또한 루프보다 훨씬 간결합니다.
제안 된 방법은 요인 열에서 작동하지 않습니다. 이 개선을 제안하고 싶습니다.
safe.ifelse <- function(cond, yes, no) {
class.y <- class(yes)
if (class.y == "factor") {
levels.y = levels(yes)
}
X <- ifelse(cond,yes,no)
if (class.y == "factor") {
X = as.factor(X)
levels(X) = levels.y
} else {
class(X) <- class.y
}
return(X)
}
그건 그렇고 : ifelse sucks ... 큰 힘으로 큰 책임 이옵니다. 즉 1x1 행렬 및 / 또는 숫자 (예 : 추가해야 할 때)의 유형 변환은 괜찮지 만 ifelse의 유형 변환은 분명히 원하지 않습니다. 나는 지금 여러 번 ifelse의 동일한 '버그'에 부딪 쳤고 그것은 단지 내 시간을 훔치는 것을 계속합니다 :-(
FW
The answer provided by @fabian-werner is great, but objects can have multiple classes, and "factor" may not necessarily be the first one returned by class(yes)
, so I suggest this small modification to check all class attributes:
safe.ifelse <- function(cond, yes, no) {
class.y <- class(yes)
if ("factor" %in% class.y) { # Note the small condition change here
levels.y = levels(yes)
}
X <- ifelse(cond,yes,no)
if ("factor" %in% class.y) { # Note the small condition change here
X = as.factor(X)
levels(X) = levels.y
} else {
class(X) <- class.y
}
return(X)
}
I have also submitted a request with the R Development team to add a documented option to have base::ifelse() preserve attributes based on user selection of which attributes to preserve. The request is here: https://bugs.r-project.org/bugzilla/show_bug.cgi?id=16609 - It has already been flagged as "WONTFIX" on the grounds that it has always been the way it is now, but I have provided a follow-up argument on why a simple addition might save a lot of R users headaches. Perhaps your "+1" in that bug thread will encourage the R Core team to take a second look.
EDIT: Here's a better version that allows the user to specify which attributes to preserve, either "cond" (default ifelse() behaviour), "yes", the behaviour as per the code above, or "no", for cases where the attributes of the "no" value are better:
safe_ifelse <- function(cond, yes, no, preserved_attributes = "yes") {
# Capture the user's choice for which attributes to preserve in return value
preserved <- switch(EXPR = preserved_attributes, "cond" = cond,
"yes" = yes,
"no" = no);
# Preserve the desired values and check if object is a factor
preserved_class <- class(preserved);
preserved_levels <- levels(preserved);
preserved_is_factor <- "factor" %in% preserved_class;
# We have to use base::ifelse() for its vectorized properties
# If we do our own if() {} else {}, then it will only work on first variable in a list
return_obj <- ifelse(cond, yes, no);
# If the object whose attributes we want to retain is a factor
# Typecast the return object as.factor()
# Set its levels()
# Then check to see if it's also one or more classes in addition to "factor"
# If so, set the classes, which will preserve "factor" too
if (preserved_is_factor) {
return_obj <- as.factor(return_obj);
levels(return_obj) <- preserved_levels;
if (length(preserved_class) > 1) {
class(return_obj) <- preserved_class;
}
}
# In all cases we want to preserve the class of the chosen object, so set it here
else {
class(return_obj) <- preserved_class;
}
return(return_obj);
} # End safe_ifelse function
The reason why this won't work is because, ifelse() function converts the values to factors. A nice workaround would be to convert it to characters before evaluating it.
dates <- as.Date(c('2011-01-01','2011-01-02','2011-01-03','2011-01-04','2011-01-05'))
dates_new <- dates - 1
dates <- as.Date(ifelse(dates =='2011-01-01',as.character(dates_new),as.character(dates)))
This wouldn't require any library apart from base R.
'Programing' 카테고리의 다른 글
자기 유형 주석에서 이것과 자기의 차이점은 무엇입니까? (0) | 2020.06.30 |
---|---|
개발 코드 및 프로덕션 코드를 어떻게 유지 관리합니까? (0) | 2020.06.30 |
SSL은 실제로 어떻게 작동합니까? (0) | 2020.06.30 |
HttpURLConnection 연결 프로세스를 설명 할 수 있습니까? (0) | 2020.06.30 |
IE11에서 "브라우저 모드"를 다시 가져 오는 방법은 무엇입니까? (0) | 2020.06.30 |