programing

ifelse()가 Date 개체를 숫자 개체로 변환하지 않도록 방지하는 방법

testmans 2023. 6. 19. 21:18
반응형

ifelse()가 Date 개체를 숫자 개체로 변환하지 않도록 방지하는 방법

는 기을사용있다니습 을 하고 있습니다.ifelse()날짜 벡터를 조작합니다.나는 그 결과가 수업이 될 것이라고 예상했습니다.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"

dplyr::if_else

릴리스 정보에서:

[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:

및"길이와속차동벡일터한포및함이성원차▁dim(벡터)포▁of함▁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"

다음 참고 사항:해들리가 집을 지었군요if_else결과 클래스를 보존하는 magritr/dplyr/dplyr 패키지의 magritr/dplyr 복합체로 변환합니다.

DWin의 설명은 정확합니다.저는 이것을 가지고 잠시 동안 장난을 치고 싸웠으며, 그 후에 제가 단순히 수업을 강요할 수 있다는 것을 깨달았습니다.

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()로부터 받는 성과 수익에 대한 작은 대가라고 생각합니다.게다가 여전히 루프보다 훨씬 더 간결합니다.

이것이 작동하지 않는 이유는 ifelse() 함수가 값을 요인으로 변환하기 때문입니다.평가하기 전에 문자로 변환하는 것이 좋습니다.

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)))

이것은 기본 R 외에 어떤 라이브러리도 필요하지 않습니다.

제안된 방법은 요인 열에서 사용할 수 없습니다.저는 이 개선을 제안하고 싶습니다.

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)
}

그건 그렇고, 안 그러면...큰 힘을 가지면 책임감이 커집니다. 즉, 1x1 행렬 및/또는 숫자(예를 들어 추가해야 할 때)의 유형 변환은 괜찮지만 이러한 유형 변환은 분명히 원하지 않습니다.나는 지금 다른 아이들의 똑같은 '버그'를 여러 번 마주쳤고 그것은 내 시간을 계속 훔칩니다 :-(

FW

@fabian-werner가 제공한 답변은 훌륭하지만 객체는 여러 클래스를 가질 수 있으며 "factor"가 반환된 첫 번째 클래스가 아닐 수 있습니다.class(yes)따라서 모든 클래스 속성을 확인하기 위해 다음과 같은 작은 수정을 제안합니다.

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)
    }

저는 또한 보존할 속성의 사용자 선택에 따라 base::ifelse()가 속성을 보존하도록 문서화된 옵션을 추가해 달라는 요청을 R 개발 팀에 제출했습니다.요청은 여기에 있습니다: https://bugs.r-project.org/bugzilla/show_bug.cgi?id=16609 - 현재와 같은 방식이라는 이유로 이미 "WONTFIX"로 플래그가 지정되었지만, 간단한 추가로 많은 R 사용자의 두통을 줄일 수 있는 이유에 대한 후속 주장을 제공했습니다.아마도 그 버그 스레드에 있는 당신의 "+1"이 R Core 팀이 다시 보도록 격려할 것입니다.

편집: 사용자가 "초"(기본 ifelse() 동작), "예", 위의 코드에 따른 동작 또는 "아니오" 값의 속성이 더 나은 경우 "아니오" 중에서 보존할 속성을 지정할 수 있는 더 나은 버전은 다음과 같습니다.

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

여기서 인덱싱을 사용하는 것이 어떻습니까?

> dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04', '2011-01-05'))
> dates[dates == '2011-01-01'] <- NA
> str(dates)
 Date[1:5], format: NA "2011-01-02" "2011-01-03" "2011-01-04" "2011-01-05"

언급URL : https://stackoverflow.com/questions/6668963/how-to-prevent-ifelse-from-turning-date-objects-into-numeric-objects

반응형