Пример утверждения, эквивалентный в R
У меня есть переменная в фрейме данных, где одно из полей обычно имеет 7-8 значений. Я хочу, чтобы они разделили их на 3 или 4 новые категории в пределах новой переменной внутри фрейма данных. Каков наилучший подход?
Я бы использовал оператор CASE, если бы был в SQL-подобном инструменте, но не уверен, как атаковать это в R.
Любая помощь, которую вы можете предоставить, будет высоко оценена!
Ответы
Ответ 1
Посмотрите на функцию cases
из пакета memisc
. Он реализует функциональность case с двумя различными способами ее использования.
Из примеров в пакете:
z1=cases(
"Condition 1"=x<0,
"Condition 2"=y<0,# only applies if x >= 0
"Condition 3"=TRUE
)
где x
и y
- два вектора.
Ответ 2
Если вы получили 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"))
Ответ 3
Здесь используется способ 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
Ответ 4
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'
})
Ответ 5
Я не вижу предложения для "переключателя". Пример кода (запустите его):
x <- "three";
y <- 0;
switch(x,
one = {y <- 5},
two = {y <- 12},
three = {y <- 432})
y
Ответ 6
Вы можете использовать recode из пакета автомобилей:
library(ggplot2) #get data
library(car)
daimons$new_var <- recode(diamonds$clarity , "'I1' = 'low';'SI2' = 'low';else = 'high';")[1:10]
Ответ 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"
Если вы укажете категории, которые вы хотите в заказе, соответствующем переназначению, вы можете использовать фактор или числовые переменные в качестве индекса:
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
, которое может вызвать проблемы, поскольку большинство людей видят факторы, отображаемые как символ, и делают неверное предположение о том, что все функции будут обрабатывать их как таковые.
Ответ 8
Мне не нравится ни одно из них, они не понятны читателю или потенциальному пользователю. Я просто использую анонимную функцию, синтаксис не такой гладкий, как аргумент case, но оценка похожа на аргумент case, а не на то, что это больно. это также предполагает, что вы оцениваете его там, где определены ваши переменные.
result <- ( function() { if (x==10 | y< 5) return('foo')
if (x==11 & y== 5) return('bar')
})()
все из них() необходимо заключить и оценить анонимную функцию.
Ответ 9
case_when()
, который был добавлен в dplyr в мае 2016 года, решает эту проблему аналогично 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"
)
)
Ответ 10
Фактический пример может оказаться неправильным. Если это фактор, который, скорее всего, просто устанавливает уровни фактора соответствующим образом.
Скажите, что у вас есть фактор с буквами от A до E, как это.
> 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
Чтобы присоединиться к уровням B и C и называть его BC, просто измените имена этих уровней на 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
Результат по желанию.
Ответ 11
Если вы хотите иметь sql-подобный синтаксис, вы можете просто использовать пакет sqldf
. Функция, которая будет использоваться, также является именем sqldf
, а синтаксис выглядит следующим образом
sqldf(<your query in quotation marks>)
Ответ 12
Вы можете использовать функцию base
merge
для задач переназначения в стиле case:
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
Ответ 13
Смешивание plyr::mutate
и dplyr::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]
Бонусные баллы, если столбец может выйти из мутате как фактор вместо char! Последняя строка оператора 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