program story

R에서 동등한 Case 문

inputbox 2020. 10. 29. 08:05
반응형

R에서 동등한 Case 문


필드 중 하나에 일반적으로 7-8 개의 값이있는 데이터 프레임에 변수가 있습니다. 데이터 프레임 내의 새 변수 내에서 3 개 또는 4 개의 새 범주를 축소하고 싶습니다. 가장 좋은 방법은 무엇입니까?

SQL과 같은 도구를 사용했지만 R에서 이것을 공격하는 방법을 잘 모르겠다면 CASE 문을 사용합니다.

당신이 제공 할 수있는 어떤 도움이라도 대단히 감사 할 것입니다!


패키지 cases기능을 살펴보십시오 memisc. 사용하는 두 가지 방법으로 케이스 기능을 구현합니다. 패키지의 예에서 :

z1=cases(
    "Condition 1"=x<0,
    "Condition 2"=y<0,# only applies if x >= 0
    "Condition 3"=TRUE
    )

여기서, x그리고 y두 개의 벡터이다.

참조 : memisc 패키지 , 사례 예


case_when()2016 년 5 월에 dplyr에 추가 된은 memisc::cases().

예를 들면 :

library(dplyr)
mtcars %>% 
  mutate(category = case_when(
    .$cyl == 4 & .$disp < median(.$disp) ~ "4 cylinders, small displacement",
    .$cyl == 8 & .$disp > median(.$disp) ~ "8 cylinders, large displacement",
    TRUE ~ "other"
  )
)

dplyr 0.7.0부터,

mtcars %>% 
  mutate(category = case_when(
    cyl == 4 & disp < median(disp) ~ "4 cylinders, small displacement",
    cyl == 8 & disp > median(disp) ~ "8 cylinders, large displacement",
    TRUE ~ "other"
  )
)

그렇다면 factor표준 방법으로 수준을 변경할 수 있습니다.

df <- data.frame(name = c('cow','pig','eagle','pigeon'), 
             stringsAsFactors = FALSE)
df$type <- factor(df$name) # First step: copy vector and make it factor
# Change levels:
levels(df$type) <- list(
    animal = c("cow", "pig"),
    bird = c("eagle", "pigeon")
)
df
#     name   type
# 1    cow animal
# 2    pig animal
# 3  eagle   bird
# 4 pigeon   bird

간단한 함수를 래퍼로 작성할 수 있습니다.

changelevels <- function(f, ...) {
    f <- as.factor(f)
    levels(f) <- list(...)
    f
}

df <- data.frame(name = c('cow','pig','eagle','pigeon'), 
                 stringsAsFactors = TRUE)

df$type <- changelevels(df$name, animal=c("cow", "pig"), bird=c("eagle", "pigeon"))

switch문을 사용하는 방법은 다음과 같습니다 .

df <- data.frame(name = c('cow','pig','eagle','pigeon'), 
                 stringsAsFactors = FALSE)
df$type <- sapply(df$name, switch, 
                  cow = 'animal', 
                  pig = 'animal', 
                  eagle = 'bird', 
                  pigeon = 'bird')

> df
    name   type
1    cow animal
2    pig animal
3  eagle   bird
4 pigeon   bird

이것의 한 가지 단점은 animal각 항목에 대해 카테고리 이름 ( 등) 을 계속 작성해야한다는 것 입니다. 아래와 같이 범주를 정의 할 수있는 것이 구문 적으로 더 편리합니다 ( R의 데이터 프레임에 열을 추가하는 방법은 매우 유사한 질문 참조 )

myMap <- list(animal = c('cow', 'pig'), bird = c('eagle', 'pigeon'))

어떻게 든이 매핑을 "반전"하고 싶습니다. 내 자신의 invMap 함수를 작성합니다.

invMap <- function(map) {
  items <- as.character( unlist(map) )
  nams <- unlist(Map(rep, names(map), sapply(map, length)))
  names(nams) <- items
  nams
}

그런 다음 위의지도를 다음과 같이 반전합니다.

> invMap(myMap)
     cow      pig    eagle   pigeon 
"animal" "animal"   "bird"   "bird" 

그리고 이것을 사용 type하여 데이터 프레임에 열 을 추가하는 것은 쉽습니다 .

df <- transform(df, type = invMap(myMap)[name])

> df
    name   type
1    cow animal
2    pig animal
3  eagle   bird
4 pigeon   bird

Imho, 가장 간단하고 보편적 인 코드 :

dft=data.frame(x = sample(letters[1:8], 20, replace=TRUE))
dft=within(dft,{
    y=NA
    y[x %in% c('a','b','c')]='abc'
    y[x %in% c('d','e','f')]='def'
    y[x %in% 'g']='g'
    y[x %in% 'h']='h'
})

'스위치'에 대한 제안이 보이지 않습니다. 코드 예제 (실행) :

x <- "three";
y <- 0;
switch(x,
       one = {y <- 5},
       two = {y <- 12},
       three = {y <- 432})
y

거기에있다 switch문하지만 나는 내가 그것을해야한다 생각하는 방식으로 작동 얻을 수가 없다. 예제를 제공하지 않았으므로 요인 변수를 사용하여 하나를 만들 것입니다.

 dft <-data.frame(x = sample(letters[1:8], 20, replace=TRUE))
 levels(dft$x)
[1] "a" "b" "c" "d" "e" "f" "g" "h"

재 할당에 적합한 순서로 원하는 범주를 지정하는 경우 요인 또는 숫자 변수를 인덱스로 사용할 수 있습니다.

c("abc", "abc", "abc", "def", "def", "def", "g", "h")[dft$x]
 [1] "def" "h"   "g"   "def" "def" "abc" "h"   "h"   "def" "abc" "abc" "abc" "h"   "h"   "abc"
[16] "def" "abc" "abc" "def" "def"

dft$y <- c("abc", "abc", "abc", "def", "def", "def", "g", "h")[dft$x] str(dft)
'data.frame':   20 obs. of  2 variables:
 $ x: Factor w/ 8 levels "a","b","c","d",..: 4 8 7 4 6 1 8 8 5 2 ...
 $ y: chr  "def" "h" "g" "def" ...

나중에 두 가지 다른 스위치 기능이 있다는 것을 알게되었습니다. 일반적인 기능은 아니지만 switch.numeric또는 로 생각해야합니다 switch.character. 첫 번째 인수가 R '인자'인 switch.numeric경우 대부분의 사람들이 요소가 문자로 표시되고 모든 함수가이를 처리 할 것이라는 잘못된 가정을하기 때문에 문제를 일으킬 가능성 이있는 행동이 발생합니다.


자동차 패키지에서 레코딩을 사용할 수 있습니다.

library(ggplot2) #get data
library(car)
daimons$new_var <- recode(diamonds$clarity , "'I1' = 'low';'SI2' = 'low';else = 'high';")[1:10]

i dont like any of these, they are not clear to the reader or the potential user. I just use an anonymous function, the syntax is not as slick as a case statement, but the evaluation is similar to a case statement and not that painful. this also assumes your evaluating it within where your variables are defined.

result <- ( function() { if (x==10 | y< 5) return('foo') 
                         if (x==11 & y== 5) return('bar')
                        })()

all of those () are necessary to enclose and evaluate the anonymous function.


I am using in those cases you are referring switch(). It looks like a control statement but actually, it is a function. The expression is evaluated and based on this value, the corresponding item in the list is returned.

switch works in two distinct ways depending whether the first argument evaluates to a character string or a number.

What follows is a simple string example which solves your problem to collapse old categories to new ones.

For the character-string form, have a single unnamed argument as the default after the named values.

newCat <- switch(EXPR = category,
       cat1   = catX,
       cat2   = catX,
       cat3   = catY,
       cat4   = catY,
       cat5   = catZ,
       cat6   = catZ,
       "not available")

A case statement actually might not be the right approach here. If this is a factor, which is likely is, just set the levels of the factor appropriately.

Say you have a factor with the letters A to E, like this.

> a <- factor(rep(LETTERS[1:5],2))
> a
 [1] A B C D E A B C D E
Levels: A B C D E

To join levels B and C and name it BC, just change the names of those levels to BC.

> levels(a) <- c("A","BC","BC","D","E")
> a
 [1] A  BC BC D  E  A  BC BC D  E 
Levels: A BC D E

The result is as desired.


If you want to have sql-like syntax you can just make use of sqldf package. Tthe function to be used is also names sqldf and the syntax is as follows

sqldf(<your query in quotation marks>)

You can use the base function merge for case-style remapping tasks:

df <- data.frame(name = c('cow','pig','eagle','pigeon','cow','eagle'), 
                 stringsAsFactors = FALSE)

mapping <- data.frame(
  name=c('cow','pig','eagle','pigeon'),
  category=c('animal','animal','bird','bird')
)

merge(df,mapping)
# name category
# 1    cow   animal
# 2    cow   animal
# 3  eagle     bird
# 4  eagle     bird
# 5    pig   animal
# 6 pigeon     bird

Mixing plyr::mutate and dplyr::case_when works for me and is readable.

iris %>%
plyr::mutate(coolness =
     dplyr::case_when(Species  == "setosa"     ~ "not cool",
                      Species  == "versicolor" ~ "not cool",
                      Species  == "virginica"  ~ "super awesome",
                      TRUE                     ~ "undetermined"
       )) -> testIris
head(testIris)
levels(testIris$coolness)  ## NULL
testIris$coolness <- as.factor(testIris$coolness)
levels(testIris$coolness)  ## ok now
testIris[97:103,4:6]

Bonus points if the column can come out of mutate as a factor instead of char! The last line of the case_when statement, which catches all un-matched rows is very important.

     Petal.Width    Species      coolness
 97         1.3  versicolor      not cool
 98         1.3  versicolor      not cool  
 99         1.1  versicolor      not cool
100         1.3  versicolor      not cool
101         2.5  virginica     super awesome
102         1.9  virginica     super awesome
103         2.1  virginica     super awesome

참고URL : https://stackoverflow.com/questions/4622060/case-statement-equivalent-in-r

반응형