2016-01-23 3 views
3

Я работаю в R с файловой рамкой, состоящей из числовой переменной и символьной переменной. Мой dataframe DF выглядит следующим образом (я добавляю версию dput в заключительной части):Странное поведение между функциями cut и ifelse в R

a1 b1 
1 a 10.15 
2 a 25.10 
3 a 32.40 
4 a 56.70 
5 a 89.02 
6 b 90.50 
7 b 78.53 
8 b 98.12 
9 b 34.30 
10 b 99.75 

DF В переменной a1 переменные групп и b1 является числовым переменным. Затем появляется дилемма. Я хочу создать новую переменную с именем c1 с помощью функции cut и рассмотреть группу, сохраненную в a1. По этой причине я совмещаю обе функции ifelse() и cut() в следующей строке коды:

DF$c1=ifelse(DF$a1=="a", 
       cut(DF$b1,breaks = c(0,25,50,70,max(DF$b1)),right = TRUE,include.lowest = TRUE), 
       ifelse(DF$a1=="b", 
         cut(DF$b1,breaks = c(0,50,max(DF$b1)),right = TRUE,include.lowest = TRUE),NA)) 

Строка коды работает нормально, но есть запутанное результат, ибо он новые ценности, созданные в c1. Вместо того, чтобы показывать коэффициент, cut() возвращает целые числа. Затем я получил этот результат:

table(DF$c1,exclude=NULL) 

    1 2 3 4 <NA> 
    2 6 1 1 0 

Несмотря на создание разрывов, целые выделенные в c1 изменить результат. Этого не происходит, когда я работаю без ifelse, но в этом случае я не согласен с условиями над группой. Например, следующая строка коды возвращает этот результат:

DF$c1=cut(DF$b1,breaks = c(0,25,50,70,max(DF$b1)),right = TRUE,include.lowest = TRUE) 

table(DF$c1,exclude=NULL) 

    [0,25] (25,50] (50,70] (70,99.8]  <NA> 
     1   3   1   5   0 

Я хотел бы знать, как разрешить эту проблему между ifelse() и cut() функциями, так как возвращаемые числа производят различия в конечном итоге. В этом примере я работаю только с двумя группами для переменной a1, но у меня есть большая база данных со многими группами. Именно по этой причине я совмещаю функции для получения разных сокращений для каждой группы. Также значения изменений могут измениться, поэтому включение меток вручную может быть длинным. Возможно ли, что комбинация этих двух функций вернет правильные метки для каждой группы (фактора) вместо целых чисел. Версия моего dataframe DFdput() является следующим:

DF<-structure(list(a1 = c("a", "a", "a", "a", "a", "b", "b", "b", 
"b", "b"), b1 = c(10.15, 25.1, 32.4, 56.7, 89.02, 90.5, 78.53, 
98.12, 34.3, 99.75)), .Names = c("a1", "b1"), row.names = c(NA, 
-10L), class = "data.frame") 

Спасибо за вашу помощь!

ответ

3

Проблема заключается в том, что и cut() вывести коэффициент, но что, поскольку они имеют разные уровни, они принудительно привязаны к целому. Раствор может быть, чтобы окружить cut() с as.character(), сохраняя тем самым уровни для принуждения, а затем factor() весь выход:

DF$c1=factor(ifelse(DF$a1=="a", 
      as.character(cut(DF$b1,breaks = c(0,25,50,70,max(DF$b1)),right = TRUE,include.lowest = TRUE)), 
      ifelse(DF$a1=="b", 
        as.character(cut(DF$b1,breaks = c(0,50,max(DF$b1)),right = TRUE,include.lowest = TRUE)),NA))) 

DF 

    a1 b1  c1 
1 a 10.15 [0,25] 
2 a 25.10 (25,50] 
3 a 32.40 (25,50] 
4 a 56.70 (50,70] 
5 a 89.02 (70,99.8] 
6 b 90.50 (50,99.8] 
7 b 78.53 (50,99.8] 
8 b 98.12 (50,99.8] 
9 b 34.30 [0,50] 
10 b 99.75 (50,99.8] 
+0

Да, но как вы разбираете фактор? –

+0

Что вы имеете в виду? Сортировка строк в кадре данных? или уровни? – scoa

+0

Когда вы конвертируете в символ, разрывы коэффициентов не выравниваются правильно, поэтому, когда вы делаете это с помощью c1, порядок фактора не упорядочен должным образом. Или когда вы рисуете с использованием фактора в качестве переменной x, порядок неверен. –

2

@scoa является правильным; вы пытаетесь объединить два фактора с разными уровнями, поэтому ваши результаты становятся принудительными к целым числам, и вы теряете уровни. Вот еще один подход с меньшим форм-фактором, который будет более масштабируемым.

Во-первых, сделать именованный список всех перерывов:

breaks <- list('a' = c(0, 25, 50, 70, max(DF$b1)), 'b' = c(0, 50, max(DF$b1))) 
breaks 

> $a 
>  0 25 50 70 99.75 
> $b 
>  0 50 99.75 

Затем использовать unlist(list(some, factors)) (или в данном случае, lapply), который аккуратно сливает факторы, сохраняя все уровни. (Это волшебство, это одна из тех встроенных функций, которая на самом деле не очевидна.)

DF$c1 <- unlist(lapply(1:length(breaks), 
        function(x){cut(DF[DF$a1 == names(breaks[x]), 'b1'], 
            breaks = breaks[[x]], 
            right = TRUE, 
            include.lowest = TRUE)} 
        )) 
DF 

> a1 b1  c1 
> 1 a 10.15 [0,25] 
> 2 a 25.10 (25,50] 
> 3 a 32.40 (25,50] 
> 4 a 56.70 (50,70] 
> 5 a 89.02 (70,99.8] 
> 6 b 90.50 (50,99.8] 
> 7 b 78.53 (50,99.8] 
> 8 b 98.12 (50,99.8] 
> 9 b 34.30 [0,50] 
> 10 b 99.75 (50,99.8] 

Это в конечном счете, 2 строки кода, и должны быть надежными в большем, более сложного набора данных.

2

Это не прямой ответ на ваш вопрос, а альтернативный подход к общей задаче.

Потому что у вас есть «большая база данных со многими группами [с] различные разрезы для каждой группы», мне кажется, что код со многими вложенной ifelse скоро может получить довольно грязно. Возможно, дело вкуса, но я думаю, что код будет легче читать и поддерживать, если вместо этого вы сохраните breaks для каждой группы в отдельной таблице.

Вот как вы можете сделать это с помощью data.table:

library(data.table) 
dt_brk <- data.table(grp = c("a", "a", "a", "a", "a", "b", "b", "b"), 
        brk = c(0, 25, 50, 70, Inf, 0, 50, Inf)) 

Обратите внимание, что я использую Inf в качестве верхнего предела разрывов, а не max(your-values)

Мы преобразовать данные кадра «DF» к data.table используя setDT. Затем для каждого уровня «a1» (by = a1) мы используем breaks из «dt_brk», где «grp» равно «a1» (dt_brk[grp == a1, brk]).

setDT(DF)[, c1 := as.character(cut(b1, breaks = dt_brk[grp == a1, brk])), by = a1] 

DF 
#  a1 b1  c1 
# 1: a 10.15 (0,25] 
# 2: a 25.10 (25,50] 
# 3: a 32.40 (25,50] 
# 4: a 56.70 (50,70] 
# 5: a 89.02 (70,Inf] 
# 6: b 90.50 (50,Inf] 
# 7: b 78.53 (50,Inf] 
# 8: b 98.12 (50,Inf] 
# 9: b 34.30 (0,50] 
# 10: b 99.75 (50,Inf] 

 Смежные вопросы

  • Нет связанных вопросов^_^