Подтвердить что ты не робот

Пример утверждения, эквивалентный в R

У меня есть переменная в фрейме данных, где одно из полей обычно имеет 7-8 значений. Я хочу, чтобы они разделили их на 3 или 4 новые категории в пределах новой переменной внутри фрейма данных. Каков наилучший подход?

Я бы использовал оператор CASE, если бы был в SQL-подобном инструменте, но не уверен, как атаковать это в R.

Любая помощь, которую вы можете предоставить, будет высоко оценена!

4b9b3361

Ответ 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