Расчет процентного значения (на основе максимального значения) для каждого элемента в df; однако в указанных столбцах

Без сложного объяснения создадим небольшой примерный фрейм данных:

A <- c(1,2,3,4)
B <- c(3,4,5,7)
C <- c(3,4,7,3)
D <- c(8,3,2,4)
df <- data.frame(A,B,C,D)

> df
  A B C D
1 1 3 3 8
2 2 4 4 3
3 3 5 7 2
4 4 7 3 4

Я хотел бы вычислить процентные значения в столбцах A, B и C, используя apply функции. Процентное значение, основанное на максимальном значении из каждой строки, другими словами:

%_to_be_calculated <- df[i,j] * 100 / max(df[i,1:3])

где j индекс столбца A, B или C; i следующих строк в таблице.

Желаемый результат:

  A     B       C       D
1 33.33 100     100     8
2 50    100     100     3
3 42.85 71.42   100     2
4 57.14 100     42.85   4

Мое решение:

apply(df,1,function(i) lapply(i[1:3],function(j) j*100/max(i[1:3])))

Он работает, однако возвращает список списков ... Я хотел бы иметь хороший df, не могли бы вы подсказать, как заменить значения в текущем df?

Спасибо.


person Adamm    schedule 17.07.2018    source источник


Ответы (3)


Есть несколько способов сделать это.

Обычный apply способ:

df[1:3] <- t(apply(df[1:3], 1, function(x) x/max(x) * 100))
df

#         A         B         C D
#1 33.33333 100.00000 100.00000 8
#2 50.00000 100.00000 100.00000 3
#3 42.85714  71.42857 100.00000 2
#4 57.14286 100.00000  42.85714 4

что также можно сделать:

df[1:3] <- df[1:3] * 100/apply(df[1:3], 1, max)

Более быстрый подход - использовать do.call и pmax

df[1:3] <- df[1:3] * 100 /do.call(pmax, df[1:3])
person Ronak Shah    schedule 17.07.2018
comment
Также df[-4] / matrixStats::rowMaxs(as.matrix(df[-4])) - person David Arenburg; 17.07.2018
comment
Спасибо за помощь! В этом контексте я должен более внимательно рассмотреть pmax и do.call. - person Adamm; 17.07.2018

Хотя мне очень нравится решение _1 _ + _ 2_, но часто, когда у вас есть четко определенная проблема, самое простое решение - заключить ее в циклы, а затем подумать о том, как оптимизировать.

df2 <- df
for (i in 1:nrow(df)) {
  mi <- max(df[i, 1:3])
  for (j in 1:3) {
    df2[i, j] <- df[i, j] * 100 / mi
  }
}
df2
         A         B         C D
1 33.33333 100.00000 100.00000 8
2 50.00000 100.00000 100.00000 3
3 42.85714  71.42857 100.00000 2
4 57.14286 100.00000  42.85714 4

Это решает проблему, и вы видите, что внутренний цикл очень легко векторизовать:

for (i in 1:nrow(df)) {
  mi <- max(df[i, 1:3]) 
  df2[i, 1:3] <- df[i, 1:3] * 100 / mi
}

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

person sindri_baldur    schedule 17.07.2018
comment
Извините, если это прозвучит снисходительно, я также намерен помочь, разделяя этот принцип. - person sindri_baldur; 17.07.2018

используя data.table:

df <- data.table(A,B,C,D)
df[,
   c(
     lapply(.SD, function(x) x/do.call(pmax,.SD[,.(A,B,C)])*100),
     D=list(D)
     ),
   .SDcols=c('A','B','C')
   ]
person user2391020    schedule 17.07.2018
comment
Но это дает разные результаты. - person rar; 17.07.2018