案例陈述等同于R

我有一个数据框中的variables,其中一个字段通常有7-8个值。 我想在数据框中的一个新variables中将它们分成3或4个新的类别。 什么是最好的方法?

如果我使用类似SQL的工具,但是不确定如何在R中攻击,我会使用CASE语句。

任何帮助你可以提供将非常感激!

看看memisc软件包中的casesfunction。 它使用两种不同的方式来实现案例function。 从包中的例子:

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

其中xy是两个向量。

如果你有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' }) 

我没有看到“转换”的build议。 代码示例(运行它):

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

您可以使用汽车包装中的重新编码:

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

我不喜欢这些,他们不清楚读者或潜在的用户。 我只是使用一个匿名函数,语法不像一个case语句那么漂亮,但是评估类似于一个case语句,而不是那么痛苦。 这也假定你在你的variables定义的地方进行评估。

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

所有这些()都必须包含和评估匿名函数。

有一个switch语句,但我似乎无法按照我认为应该的方式工作。 既然你没有提供一个例子,我将使用一个因子variables:

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

如果您按照适合重新分配的顺序指定所需的类别,则可以使用因子或数字variables作为索引:

 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" ... 

后来我才知道实际上有两种不同的开关function。 这不是generics函数,但你应该把它想成switch.numericswitch.character 。 如果你的第一个参数是一个R因子,你会得到switch.numeric行为,这很可能会导致问题,因为大多数人看到的因素显示为字符,并作出不正确的假设,所有的function将如此处理。

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

案例陈述实际上可能不是这里的正确方法。 如果这是一个可能的因素,只要适当地设置因素的水平。

假设你有一个字母A到E的因素,像这样。

 > a <- factor(rep(LETTERS[1:5],2)) > a [1] ABCDEABCDE Levels: ABCDE 

要joinB级和C级并命名为BC,只需将这些级别的名称更改为BC。

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

结果是根据需要。

如果你想使用类似sql的语法,你可以使用sqldf包。 要使用的函数也是名称sqldf ,语法如下

 sqldf(<your query in quotation marks>) 

您可以使用basefunctionmerge案例样式的重新映射任务:

 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 

混合plyr::mutatedplyr::case_when为我工作,是可读的。

 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] 

奖励点,如果列可以出来突变作为一个因素,而不是字符! case_when语句的最后一行,捕获所有不匹配的行是非常重要的。

  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