2014-09-25 2 views
2

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

dfs <- structure(list(TZ = structure(list(row.names = c(168L, 302L), 
    type = c(1.5, 25.35), zone = c(43.53, 87.65)), .Names = c("row.names", 
"type", "zone"), class = "data.frame", row.names = c(NA, -2L)), 
    Weight = structure(list(row.names = c(168L, 302L), `1` = c(TRUE, 
    FALSE), `2` = c(TRUE, TRUE)), .Names = c("row.names", "1", 
    "2"), class = "data.frame", row.names = c(NA, -2L)), Number = structure(list(
     row.names = c(168L, 302L), `1` = c(6L, 9L), `2` = c(8L, 
     6L)), .Names = c("row.names", "1", "2"), class = "data.frame", row.names = c(NA, 
    -2L))), .Names = c("TZ", "Weight", "Number")) 

, где TZ служит в качестве классификатора/идентификатор данных, Weight содержит веса для использования в weighted.mean (мне нужно преобразовать TRUE 1 и FALSE до 0), и Number содержит данные, которые я хочу использовать для расчета средневзвешенных значений. Отметим, что структура отличается от Weight и Number, но важноrow.names согласовано во всех кадрах данных, и именно так я могу связать данные между кадром данных. Мои реальные данные содержат ряд дополнительных фреймов данных, для которых я хочу выполнять те же операции (они согласуются друг с другом и с этим простым примером).

В результате я "м пытаюсь достичь

result <- structure(list(row.names = c(168L, 302L), type = c(1.5, 23.35 
), zone = c(43.53, 87.65), Num.Wht = c(7L, 6L)), .Names = c("row.names", 
"type", "zone", "Num.Wht"), class = "data.frame", row.names = c(NA, 
-2L)) 

    row.names type zone Num.Wht 
1 168   1.50 43.53 7 
2 302   23.35 87.65 6 

где Num.Wht является средневзвешенное Number взвешенных по Weight (после преобразования в 1s и 0s). Обратите внимание, что в моих реальных данных, у меня будет много дополнительные dataframes, и, таким образом, столбцы, содержащие средневзвешенных.

Можно ли рекомендовать хорошую стратегию для производства? Я думал в первую melt затем merge мои dataframes Weight и Number, так что я мог, то и се weighted.mean

library(reshape2) 
test1 <- melt(dfs$Weight, id="row.names") 
colnames(test1)[2:3] <- c("Time", "Weight") 
test2 <- melt(dfs$Number, id="row.names") 
colnames(test2)[2:3] <- c("Time", "Number") 

Однако при использовании

test <- merge(test1, test2, by.x="row.names", by.y="row.names") 

или

test <- merge(test1, test2, by.x="test1$row.names", by.y="test$2row.names") 

Я получаю сообщение об ошибке

Error in fix.by(by.x, x) : 'by' must specify a uniquely valid column 

Я также попробовал первые merge в dataframes до переформирования, например

dat <- merge(dfs$TZ, dfs$Weight, by.x="row.names", by.y="row.names") 

Однако это дает ту же ошибку. (Любопытно, что это действительно работает в моих реальных данных.)

Я также попытался изменить row.names в Weight и Number, merge дает мне различные столбцы для Time.x и Time.y

colnames(test1) <- c("Row.names", "Time", "Weight") 
colnames(test2) <- c("Row.names", "Time", "Number") 
test <- merge(test1, test2, by.x="Row.names", by.y="Row.names") 

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

# convert weight to 1 and 0 
test$Weight <- test$Weight*1 

lapply(dfs,function(d) ddply(d, .(Time), summarize, Num.Wht=weighted.mean(test$Number,test$Weight))) 
+0

Я думаю, что некоторые из ваших проблем возникает из-за того, что вызов ' merge' с 'by =" row.names "' предполагается использовать имена ростов, а не столбцы с именем '' row.names''. –

ответ

0

Томаса, проблема слияния является то, что данные.фреймы уже имеют атрибут row.names, поэтому, когда у вас также есть столбец с именем row.names, он не знает, какой из них выбрать для слияния (отсюда сообщение 'by' должно указывать однозначно допустимый столбец).

Таким образом, изменяя все столбцы «row.names» в «идентификатор», чтобы избежать конфликтов имен, вы можете сделать это следующим образом:

#renaming columns 
dfs <- lapply(dfs, function(df){names(df)[1]<- "id";df}) 

# merging all dfs 
merged_dfs <- Reduce(function(x,y) merge(x,y, by="id"), dfs) 

# calculating weighted average 
merged_dfs$Num.Wht <- apply(merged_dfs[,4:7], 1, 
          function(x) weighted.mean(x[3:4], as.numeric(x[1:2]))) 

# getting the end result you want 
result <- merged_dfs[,-c(4:7)] 
result 
    id type zone Num.Wht 
1 168 1.50 43.53  7 
2 302 25.35 87.65  6 
+0

Спасибо Карлос, ваше решение отлично подходит для моего примера, но я не могу переименовать «row.names» для своих реальных данных. В моем примере «row.names» - это столбец, но в моих реальных данных результат получается из рода. Таким образом, переименование столбцов в моих реальных данных не переименовывает «row.names», а вместо этого первый столбец («Тип» и «1» в моем приведенном примере). Вы знаете, как я могу справиться с этой проблемой? Я попытался добавить новый столбец «id» с помощью rownames(), но это проблематично из-за разных размеров ячеек данных в моем списке. – Thomas

+0

@Thomas, если вы используете фактические 'row.names' в своем исходном наборе данных, и у вас нет столбца с именем' row.names', вы можете пропустить часть переименования столбца и выполнить слияние с ' row.names': 'Уменьшить (функция (x, y) merge (x, y, by =" row.names "), dfs)' –

+0

Спасибо Карлосу. Когда я пытаюсь это сделать, я получаю 11 предупреждений «В файле merge.data.frame (x, y, by =« row.names »): имя столбца« Row.names »дублируется в результате». (В моем реальном списке 13 фреймов данных.) – Thomas

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