R help: разделить значения на сумму, полученную через множитель

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

A <- c(1,1,2,2)
B <- c(0.2, 0.3, 1, 0.5)
C <- c(0.7, 0.5, 0, 0.9)
M <- data.table(A,B,C) 

> M
     A   B   C
[1,] 1 0.2 0.7
[2,] 1 0.3 0.5
[3,] 2 1.0 0.0
[4,] 2 0.5 0.9 

Факторы могут возникать любое количество раз. Мне удалось получить сумму на фактор с библиотекой data.table:

library(data.table)
M.dt <- data.table(M)
M.sum <- M.dt[, lapply(.SD, sum), by = A]

> M.sum
   A   B   C
1: 1 0.5 1.2
2: 2 1.5 0.9

но не знал, как идти дальше, чтобы сохранить исходный формат таблицы.

Полученная таблица должна выглядеть так:

B.1 <- c(0.4, 0.6, 0.666, 0.333)
C.1 <- c(0.583, 0.416, 0, 1)
M.1 <- cbind(A, B.1, C.1)

> M.1
     A   B.1     C.1
[1,] 1 0.400 0.58333
[2,] 1 0.600 0.41666
[3,] 2 0.666 0.00000
[4,] 2 0.333 1.00000

Расчет для первого значения в B.1 будет выглядеть следующим образом: 0,2/(0,2+0,3) = 0,4 и т. Д., Где добавляемые значения определяются коэффициентом в A.
У меня есть некоторые базовые знания R, но, несмотря на все усилия, я плохо справляюсь с матричными манипуляциями и циклами.

2 ответа

Решение

Просто разделите каждое значение в каждом столбце на sum за каждое значение в A

M[, lapply(.SD, function(x) x/sum(x)), A]
#    A         B         C
# 1: 1 0.4000000 0.5833333
# 2: 1 0.6000000 0.4166667
# 3: 2 0.6666667 0.0000000
# 4: 2 0.3333333 1.0000000

Если вы хотите обновить по ссылке, сделайте

M[, c("B", "C") := lapply(.SD, function(x) x/sum(x)), A]

Или в целом

M[, names(M)[-1] := lapply(.SD, function(x) x/sum(x)), A]

Бонусное решение для dplyr наркоманы

library(dplyr)
M %>%
  group_by(A) %>%
  mutate_each(funs(./sum(.)))

# Source: local data table [4 x 3]
# Groups: A
# 
#   A         B         C
# 1 1 0.4000000 0.5833333
# 2 1 0.6000000 0.4166667
# 3 2 0.6666667 0.0000000
# 4 2 0.3333333 1.0000000

Как и большинство проблем этого типа, вы можете использовать data.table или же plyr пакет или некоторая комбинация split, применить, объединить функции в базе R.

Для тех, кто предпочитает plyr пакет

library (dplyr)
M <- data.table(A,B,C) 

ddply(M, .(A), colwise(function(x) x/sum(x)))

Выход:

  A         B         C
1 1 0.4000000 0.5833333
2 1 0.6000000 0.4166667
3 2 0.6666667 0.0000000
4 2 0.3333333 1.0000000
Другие вопросы по тегам