2016-05-14 5 views
1

У меня есть data.frame со многими строками и столбцами, и я хочу рассчитать среднее различие каждого значения для каждого из других значений внутри группы.
Вот пример:Вычислить среднее различие для каждой строки и для каждой группы

ID value 
1 4 
1 5 
1 7 
2 8 
2 6 
2 5 
2 6 

Это то, что я хочу, чтобы вычислить:

ID value value_mean_diff 
1 4  (4-5)^2 + (4-7)^2 /groupsize = 3 
1 5  (5-4)^2 + (5-7)^2/3 
1 7  (7-4)^2 + (7-5)^2/3 
2 8  (8-6)^2 + (8-5)^2 + (8-6)^2/4 
2 6  (6-8)^2 + (6-5)^2 + (6-6)^2/4 
2 5  (5-8)^2 + (5-6)^2 + (5-6)^2/4 
2 6  (6-8)^2 + (6-6)^2 + (6-5)^2/4 

Я попытался с помощью агрегата(), но не смог заставить его работать.

ответ

1

Раствора с помощью crossjoin в data.table библиотеки с дефектом удаления дублированных строк из исходного кадра данных:

> dt <- setDT(df)[,setNames(CJ(value, value), c("value", "value1")), .(ID)][,.(value_mean_diff = sum((value-value1)^2)/.N),.(ID, value)] 
> dt 
    ID value value_mean_diff 
1: 1  4  3.333333 
2: 1  5  1.666667 
3: 1  7  4.333333 
4: 2  5  2.750000 
5: 2  6  1.250000 
6: 2  8  4.250000 

Поскольку дублированные строки всегда имеют один и те же value_mean_diff, вы всегда можете объединить их, чтобы получить все дублированные строки.

> merge(dt, df, by = c("ID", "value")) 
    ID value value_mean_diff 
1: 1  4  3.333333 
2: 1  5  1.666667 
3: 1  7  4.333333 
4: 2  5  2.750000 
5: 2  6  1.250000 
6: 2  6  1.250000 
7: 2  8  4.250000 

Update: Поскольку выше метода является большой объем памяти, вы можете воспользоваться тем, что ваши value_mean_diff = (значение - value_mean)^2 + дисперсия (значение), которые вы можете доказать путем расширения дисперсии на основе ее определения. При этом, как факт, можно рассчитать следующим образом:

> setDT(df)[, value_mean_diff := (value - mean(value))^2 + var(value) * (.N - 1)/.N, .(ID)] 
> df 
    ID value value_mean_diff 
1: 1  4  3.333333 
2: 1  5  1.666667 
3: 1  7  4.333333 
4: 2  8  4.250000 
5: 2  6  1.250000 
6: 2  5  2.750000 
7: 2  6  1.250000 

Имейте в виду, что var() функция R вычислить дисперсию выборки, так что вам нужно, чтобы преобразовать его в дисперсии генеральной совокупности путем умножения коэффициента (п -1)/n.

+0

Здравствуйте @Psidom, спасибо за ответ. Я пробовал использовать свой код для моего фреймворка, но я не уверен, что понимаю, как он работает. 'dt = setDT (train_data) [, setNames (CJ (train_data $ distance, train_data $ distance), c (" value "," value1 ")),. (train_data $ srch_id)] ​​[,. (value_mean_diff = sum ((value-value1)^2)/.N),. (train_data $ srch_id, train_data $ distance)] 'Результаты в ошибке памяти: невозможно выделить вектор размера 74.5 Gb – jranzijn

+0

Не знаете, насколько велика ваша data.frame. 'dt = setDT (train_data) [, setNames (CJ (расстояние, расстояние), c (« расстояние »,« расстояние1 »)),. (srch_id)] ​​[,. (value_mean_diff = sum ((distance-distance1)^2) /. N),. (Srch_id, distance)] ' – Psidom

+0

Еще раз спасибо, я получил 100 000 строк. Это все равно дает мне ошибку памяти. Ошибка: не может выделить вектор размера 37.3 Gb – jranzijn

0

Вот решение, используя только базовый R:

myData <- data.frame(ID=c(1,1,1,2,2,2,2), value=c(4,5,7,8,6,5,6), diff=NA) 
for(i in 1:nrow(myData)) 
    myData$diff[i] <- with(data = myData, 
     sum((value[i] - value[ID==ID[i]])**2)/length(value[ID==ID[i]])) 

myData 

    ID value  diff 
1 1  4 3.333333 
2 1  5 1.666667 
3 1  7 4.333333 
4 2  8 4.250000 
5 2  6 1.250000 
6 2  5 2.750000 
7 2  6 1.250000 
+0

Привет, Доминик, спасибо большое за ваше решение, это сработало! Для выполнения 100 000 строк потребовалось 3 минуты в 3 секунды. Я очень рад, что это сработало, спасибо снова. – jranzijn

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