案例陈述相当于R

Bti*_*rt3 72 r case

我在数据框中有一个变量,其中一个字段通常有7-8个值.我想在数据框中的一个新变量中将它们拼写为3或4个新类别.什么是最好的方法?

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

您将提供的任何帮助将不胜感激!

Eva*_*ens 27

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"
  )
)
Run Code Online (Sandbox Code Playgroud)

截至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"
  )
)
Run Code Online (Sandbox Code Playgroud)

  • 你不需要每列前面的`.$`. (4认同)
  • 是的,从 dplyr 0.7.0(2017 年 6 月 9 日发布)开始,不再需要“.$”。在最初写这个答案时,确实如此。 (2认同)

Hen*_*ico 26

casesmemisc包中查看功能.它使用两种不同的方式来实现案例功能.从包中的示例:

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

其中xy是两个矢量.

参考文献:memisc包,案例


Mar*_*rek 21

如果你有,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
Run Code Online (Sandbox Code Playgroud)

您可以编写简单的函数作为包装器:

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"))
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案。我忘了您可以使用列表作为具有旧名称和新名称的级别的参数;我的解决方案取决于保持级别的顺序,所以这样更好。 (2认同)

Pra*_*ani 17

以下是使用该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
Run Code Online (Sandbox Code Playgroud)

这样做的一个缺点是你必须继续animal为每个项目写下类别名称(等).在语法上更方便的是能够如下定义我们的类别(参见非常类似的问题如何在R中的数据框中添加列)

myMap <- list(animal = c('cow', 'pig'), bird = c('eagle', 'pigeon'))
Run Code Online (Sandbox Code Playgroud)

我们想以某种方式"反转"这种映射.我编写自己的invMap函数:

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

然后按如下方式反转上面的地图:

> invMap(myMap)
     cow      pig    eagle   pigeon 
"animal" "animal"   "bird"   "bird" 
Run Code Online (Sandbox Code Playgroud)

然后很容易使用它来添加type数据框中的列:

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

> df
    name   type
1    cow animal
2    pig animal
3  eagle   bird
4 pigeon   bird
Run Code Online (Sandbox Code Playgroud)


Gre*_*min 14

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'
})
Run Code Online (Sandbox Code Playgroud)

  • @T.Fung 您可以将第一行更改为 `y = 'else'`。不满足任何进一步条件的元素将保持不变。 (3认同)

小智 14

我没有看到"切换"的提议.代码示例(运行它):

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


42-*_*42- 7

有一个switch声明,但我似乎永远不会按照我认为应该的方式让它工作.由于您没有提供示例,我将使用因子变量创建一个:

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

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

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" ...
Run Code Online (Sandbox Code Playgroud)

后来我才知道有两种不同的开关功能.它不是通用功能,但您应该将其视为switch.numeric或者switch.character.如果你的第一个参数是一个R'因子',你就会得到switch.numeric行为,这很可能会引起问题,因为大多数人都会看到显示为字符的因素,并做出错误的假设,即所有函数都将处理它们.


Ian*_*ows 6

您可以使用汽车套餐中的重新编码:

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

  • 我只是不能支持从文本中解析它的参数的函数 (11认同)

小智 5

我不喜欢这些,他们不清楚读者或潜在用户.我只是使用匿名函数,语法不像case语句那样光滑,但评估类似于case语句而不是那么痛苦.这也假设您在定义变量的位置进行评估.

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

所有这些()都是封闭和评估匿名函数所必需的.

  • 1)功能部分是不必要的; 你可以做`结果< - (如果(x == 10 | y <5)'foo',如果(x == 11&y == 5)'bar')`.2)只有当`x`和`y`是标量时才有效; 对于向量,就像在原始问题中一样,嵌套的`ifelse`语句是必要的. (6认同)

pet*_*tzi 5

我在你所指的那些情况下使用switch()。它看起来像一个控制语句,但实际上它是一个函数。对表达式求值,并根据该值返回列表中的相应项。

switch 以两种不同的方式工作,具体取决于第一个参数的计算结果是字符串还是数字。

下面是一个简单的字符串示例,它解决了将旧类别折叠为新类别的问题。

对于字符串形式,在命名值之后有一个未命名的参数作为默认值。

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