Условная замена значений в данных.рамка


я пытаюсь понять, как условно заменить значения в фрейме данных без использования цикла. Мой фрейм данных структурирован следующим образом:

> df
          a b est
1  11.77000 2   0
2  10.90000 3   0
3  10.32000 2   0
4  10.96000 0   0
5   9.90600 0   0
6  10.70000 0   0
7  11.43000 1   0
8  11.41000 2   0
9  10.48512 4   0
10 11.19000 0   0

и dput выход такой:

structure(list(a = c(11.77, 10.9, 10.32, 10.96, 9.906, 10.7, 
11.43, 11.41, 10.48512, 11.19), b = c(2, 3, 2, 0, 0, 0, 1, 2, 
4, 0), est = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)), .Names = c("a", 
"b", "est"), row.names = c(NA, -10L), class = "data.frame")

что я хочу сделать, это проверить значение b. Если b равно 0, я хочу установить est значением a. Я понимаю, что df$est[df$b == 0] <- 23 установит все значения est в 23, когда b==0. То, что я не понимаю, как установить est в значение a когда это условие истинно. Например:

df$est[df$b == 0] <- (df$a - 5)/2.533 

дает следующее предупреждение:

Warning message:
In df$est[df$b == 0] <- (df$a - 5)/2.533 :
  number of items to replace is not a multiple of replacement length

есть ли способ, которым я могу передать соответствующую ячейку, а не вектор?

6 60

6 ответов:

так как вы условно индексируете df$est, вам также нужно условно индексировать вектор замены df$a:

index <- df$b == 0
df$est[index] <- (df$a[index] - 5)/2.533 

конечно, переменная index это временно, и я использую его, чтобы сделать код немного более readible. Вы можете написать его в один шаг:

df$est[df$b == 0] <- (df$a[df$b == 0] - 5)/2.533 

для еще лучшей читаемости, вы можете использовать within:

df <- within(df, est[b==0] <- (a[b==0]-5)/2.533)

результаты, независимо от того, какой способ вы выберете:

df
          a b      est
1  11.77000 2 0.000000
2  10.90000 3 0.000000
3  10.32000 2 0.000000
4  10.96000 0 2.352941
5   9.90600 0 1.936834
6  10.70000 0 2.250296
7  11.43000 1 0.000000
8  11.41000 2 0.000000
9  10.48512 4 0.000000
10 11.19000 0 2.443743

как и другие указали, альтернативным решением в вашем примере является использование ifelse.

попробовать данные.таблица ' s := оператор :

DT = as.data.table(df)
DT[b==0, est := (a-5)/2.533]

это быстро и коротко. Увидеть эти вопросы, для получения дополнительной информации о :=:

почему данные.таблица определена :=

когда я должен использовать := оператор data.table

Как удалить столбцы из data.frame

R self reference

вот один подход. ifelse векторизуется и проверяет все строки на нулевые значения b и заменяет est С (a - 5)/2.53 если это так.

df <- transform(df, est = ifelse(b == 0, (a - 5)/2.53, est))

The Р-Инферно, или основная R-документация объяснит, почему использование df$* не является лучшим подходом здесь. На странице справки для " [":

"индексирование по [ похоже на атомарные векторы и выбирает список указанных элементов. Оба [[ и $ выберите один элемент списка. Основное различие заключается в том, что $ не позволяет вычислять индексы, тогда как [[ делает. х$название эквивалентно X[["имя", точно = ложь]]. Кроме того, частичное совпадение поведения [[can управляется с помощью точного аргумента. "

Я рекомендую использовать Примечание. Пример:

Rgames: foo   
         x    y z  
   [1,] 1e+00 1 0  
   [2,] 2e+00 2 0  
   [3,] 3e+00 1 0  
   [4,] 4e+00 2 0  
   [5,] 5e+00 1 0  
   [6,] 6e+00 2 0  
   [7,] 7e+00 1 0  
   [8,] 8e+00 2 0  
   [9,] 9e+00 1 0  
   [10,] 1e+01 2 0  
Rgames: foo<-as.data.frame(foo)

Rgames: foo[foo$y==2,3]<-foo[foo$y==2,1]
Rgames: foo
       x y     z
1  1e+00 1 0e+00
2  2e+00 2 2e+00
3  3e+00 1 0e+00
4  4e+00 2 4e+00
5  5e+00 1 0e+00
6  6e+00 2 6e+00
7  7e+00 1 0e+00
8  8e+00 2 8e+00
9  9e+00 1 0e+00
10 1e+01 2 1e+01

другой вариант-использовать case_when

require(dplyr)

transform(df, est = case_when(
    b == 0 ~ (a - 5)/2.53, 
    TRUE   ~ est 
))

это решение становится еще более удобным, если необходимо выделить более 2 случаев, так как это позволяет избежать вложенных if_else конструктов.

вот мое решение с другой версией, чтобы решить мою проблему с if и max в строке .

my.assign <- function(col1, col2, col3){
                       if(col2==0) {col3 <- col1} else {
                       col3 <- 0
                      }
              }

my.max <- function(col1, col2, col3){
                     if(col1 >= 10 ) {max_r <- max(col2, col3, na.rm=TRUE)} 
                         else { max_r <- col2 }
              }


df$est <- with(df,mapply(my.assign,col1=a, col2=b, col3=est))
df$max_row <- with(df,mapply(my.max,col1=a, col2=b, col3=est))

> df
      a b    est max_row
1  11.77000 2  0.000    2.00
2  10.90000 3  0.000    3.00
3  10.32000 2  0.000    2.00
4  10.96000 0 10.960   10.96
5   9.90600 0  9.906    0.00
6  10.70000 0 10.700   10.70
7  11.43000 1  0.000    1.00
8  11.41000 2  0.000    2.00
9  10.48512 4  0.000    4.00
10 11.19000 0 11.190   11.19