我在一个数据框中有一个变量,其中一个字段通常有7-8个值。我想将它们合并为3或4个新类别,并将其放入数据框中的一个新变量中。什么是最好的方法?
如果我在像SQL这样的工具中,我会使用CASE语句,但不确定如何在R中解决这个问题。
非常感谢您能提供的任何帮助!
case_when()
函数是在 2016 年 5 月加入到 dplyr 中的,它解决了一个类似于 memisc::cases()
的问题。
例如,在 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"
)
)
原始回答
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"
)
)
下面是使用 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
我没有看到“switch”的建议。以下是一个代码示例(可运行):
x <- "three"
y <- 0
switch(x,
one = {y <- 5},
two = {y <- 12},
three = {y <- 432})
y
如果你有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"))
x
应该改为 changelevels
吗? - Aaron left Stack Overflow在我看来,最简单通用的代码:
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'
})
y = 'else'
。不符合任何进一步条件的元素将保持不变。 - Gregory Demin有一个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函数。它不是通用函数,而是应该将其视为switch.numeric
或switch.character
。如果您的第一个参数是R '因子',则会得到switch.numeric
行为,这很可能会导致问题,因为大多数人看到因子显示为字符并错误地假设所有函数都会将它们处理为字符。
switch()
。它看起来像一个控制语句,但实际上它是一个函数。表达式被评估并基于这个值,返回列表中对应的项。
下面是一个简单的字符串示例,解决了将旧类别折叠到新类别的问题。
switch
有两种不同的方式,取决于第一个参数是字符串还是数字。
对于字符串形式,在命名值之后有一个未命名的默认参数。
newCat <- switch(EXPR = category,
cat1 = catX,
cat2 = catX,
cat3 = catY,
cat4 = catY,
cat5 = catZ,
cat6 = catZ,
"not available")
library(ggplot2) #get data
library(car)
daimons$new_var <- recode(diamonds$clarity , "'I1' = 'low';'SI2' = 'low';else = 'high';")[1:10]
sos::findFn("recode")
可以找到doBy::recodeVar
、epicalc::recode
和memisc::recode
,但我还没有详细查看它们... - Ben Bolkerresult <- ( function() { if (x==10 | y< 5) return('foo')
if (x==11 & y== 5) return('bar')
})()
result <- (if (x==10 | y< 5) 'foo' else if (x==11 & y== 5) 'bar' )
。
2)这仅适用于 x
和 y
是标量;对于向量,就像在原始问题中一样,需要嵌套 ifelse
语句。 - Aaron left Stack Overflow
.$
。 - kath.$
。在本回答最初编写时,这是必需的。 - Evan Cortensswitch
不同,它允许你创建一个表达式序列而不是键来作为各种情况的条件。 - Dannid