2013-06-10 6 views
1

Я хочу выполнить эту простую категоризацию в кадре данных в R. Категории - 1,2,3,4 и -1. Я хочу добавить результаты этого вычисления в новый столбец в фрейме данных. «oldCol» - это имя столбца, уже находящегося в фрейме данных.Неверные результаты из числового сравнения в R

DF$newCol <- apply(DF, 1, function(row) { 
    if (row[["oldCol"]] > 10.0) 
    {result1 <- 4.0} 
    else if (row[["oldCol"]] > 2.0 && row[["oldCol"]] <= 10.0) 
    {result1 <- 3.0} 
    else if (row[["oldCol"]] > 0.5 && row[["oldCol"]] <= 2.0) 
    {result1 <- 2.0} 
    else if (row[["oldCol"]] > 0.0 && row[["oldCol"]] <= 0.5) 
    {result1 <- 1.0} 
    else 
    {result1 <- -1.0} 
    return(result1) 
}) 

Моя проблема: код делает новый столбец, но значения в нем неверны! С помощью этого точного кода цифры более 10 корректно классифицируются как класс 4, но все остальные строки содержат -1. Зачем? Алгоритм настолько прост, что это действительно беспокоит меня.

Кроме того, есть ли более элегантный способ сделать это?

+3

'apply' преобразует ваши строки в векторы, так что если ваш' DF' имеет столбцы символов, все будет преобразовано в символ ... Например: apply (data.frame (x = 1:26, y = letters), 1, function (row) class (row [["x"]])) 'возвращает символ", а не "integer". – flodel

+0

Спасибо, Бен Болкер! Это решило мою проблему: –

+0

keepData <- transform (keepData, SizeClass4 = as.numeric (as.character (cut (LeafArea, breaks = c (-Inf, 0,0.5,2,10, Inf), labels = c (-1,1: 4))))) –

ответ

3

Ваш код работает для меня:

DF <- data.frame(oldCol=c(-1,0.25,1,5,12)) 

DF$newCol <- apply(DF, 1, function(row) { 
    if (row[["oldCol"]] > 10.0) 
    {result1 <- 4.0} 
    else if (row[["oldCol"]] > 2.0 && row[["oldCol"]] <= 10.0) 
    {result1 <- 3.0} 
    else if (row[["oldCol"]] > 0.5 && row[["oldCol"]] <= 2.0) 
    {result1 <- 2.0} 
    else if (row[["oldCol"]] > 0.0 && row[["oldCol"]] <= 0.5) 
    {result1 <- 1.0} 
    else 
    {result1 <- -1.0} 
    return(result1) 
}) 

Результаты:

## oldCol newCol 
## 1 -1.00  -1 
## 2 0.25  1 
## 3 1.00  2 
## 4 5.00  3 
## 5 12.00  4 
## 

Одна альтернатива:

DF <- transform(DF, 
     newCol=as.numeric(as.character(cut(oldCol, 
      breaks=c(-Inf,0,0.5,2,10,Inf), 
      labels=c(-1,1:4))))) 

или:

library("plyr") 
DF <- mutate(DF, 
     tmpCol=cut(oldCol, 
      breaks=c(-Inf,0,0.5,2,10,Inf),labels=FALSE), 
     newCol=ifelse(tmpCol=="1",-1,as.numeric(tmpCol)-1)) 
+0

Да, когда я запускаю ваш пример кода на моей машине, он работает правильно. Однако другой кадр данных, над которым я работал первоначально, намного больше, размеры 10 000x11. Что может заставить его работать ненадлежащим образом? Я проверил режим и класс столбцов фрейма данных, и они все числовые. , , не может понять, почему работает простой пример, но не мой другой фрейм данных? –

+0

Спасибо, что проверил мой алгоритм, я волновался, что делаю что-то ужасное. Я собираюсь обновить несколько подробностей о моем фрейме данных. –

+0

И я собираюсь попробовать другие предложения. Я не очень хорошо знаком с трансформированием, но я попробую. –

2

Вот несколько проще ответ, который также принимает во внимание, что вы имеете дело с double-й годами, и поэтому будет иметь точные вопросы:

cuts = c(0, 0.5, 2, 10) + 1e-8 # example precision, pick appropriately for your problem 
           # (possibly pick a different precision for each cut point) 
DF$newCol = findInterval(DF$oldCol, cuts) 
+0

Это хорошо, но вам все равно нужно отобразить нижнюю категорию от 0 до -1 (например, 'DF $ newcol [DF $ newcol == 0] <- -1') –

+0

@BenBolker согласился, если это действительно необходимо – eddi

+0

благодаря! это было действительно полезно –