Нахождение среднего значения всех Дубликатов - PullRequest
3 голосов
/ 25 октября 2011

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

z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))
# id var
#  1   2
#  1   4
#  2   1
#  2   3
#  3   5
#  4   2

Я хотел бы вывод:

# id var
#  1   3     mean(2,4)
#  2   2     mean(1,3)
#  3   5
#  4   2

Мой текущий код:

averages<-do.call(rbind,lapply(split(z,z$id),function(chunk) mean(chunk$var)))
z<-z[order(z$id),]
z<-z[!duplicated(z$id),]
z$var<-averages

Мой код работает очень медленно и занимает примерно в 10 раз больше времени, чем метод выбора максимума.Как мне оптимизировать этот код?

Ответы [ 3 ]

5 голосов
/ 25 октября 2011

Вот более быстрое решение с использованием data.table

library(data.table)
z <- data.frame(id=sample(letters, 6e5, replace = TRUE),var = rnorm(6e5))

fn1 <- function(z){
  z$var <- ave(z$var, z$id, FUN=mean)
  return(unique(z))
}

fn2 <- function(z) {
  t(sapply(split(z,z$id), function(x) sapply(x,mean)))
}

fn3 <- function(z){
  data.table(z)[,list(var = mean(var)), 'id']
}

library(rbenchmark)
benchmark(f1 <- fn1(z), f2 <- fn2(z), f3 <- fn3(z), replications = 2)

  est replications elapsed         relative     user.self  sys.self 
1 f1 <- fn1(z)            2   3.619 8.455607     3.331    0.242          
2 f2 <- fn2(z)            2   0.586 1.369159     0.365    0.220          
3 f3 <- fn3(z)            2   0.428 1.000000     0.341    0.086   
4 голосов
/ 25 октября 2011

Я думаю split() и unsplit() - это один из способов.

dupMean <- function(x)
{
    result <- split(x[, 2], x[, 1])
    result <- lapply(result, mean)
    result <- unsplit(result, unique(x[, 1]))

    return(result)  
}

Или, чтобы сохранить строку с plyr:

require(plyr)
dupMean <- function(x)
{
    result <- split(x[, 2], x[, 1])
    result <- laply(result, mean)

    return(result)  
}

Обновление: Просто для любопытства приведено сравнение различных предлагаемых функций.Рамнат (fn3) выглядит победителем на моем компьютере.

require(plyr)
require(data.table)
require(rbenchmark)

fn1 <- function(z){
    z$var <- ave(z$var, z$id, FUN=mean)
    return(unique(z))
}

fn2 <- function(z) {
    t(sapply(split(z,z$id), function(x) sapply(x,mean)))
}

fn3 <- function(z){
    data.table(z)[,list(var = mean(var)), 'id']
}

fn4 <- function(x)
{
    result <- t(sapply(split(x,x$id), function(y) sapply(y,mean)))

    return(result)
}

fn5 <- function(x)
{
    x$var <- ave(x$var, x$id, FUN=mean)
    x <- unique(x)

    return(x)
}

fn6 <- function(x)
{
    result <- do.call(rbind,lapply(split(x,x$id),function(chunk) mean(chunk$var)))

    return(data.frame(id = unique(x[, 1]), var = result))
}

fn7 <- function(x)
{
    result <- split(x[, 2], x[, 1])
    result <- lapply(result, mean)
    result <- unsplit(result, unique(x[, 1]))


    return(data.frame(id = unique(x[, 1]), var = result))   
}


fn8 <- function(x)
{
    result <- split(x[, 2], x[, 1])
    result <- laply(result, mean)

    return(data.frame(id = unique(x[, 1]), var = result))
}



z <- data.frame(id = rep(c(1,1,2,2,3,4,5,6,6,7), 1e5), var = rnorm(1e6))

benchmark(f1 <- fn1(z), f2 <- fn2(z), f3 <- fn3(z), f4 <- fn4(z), f5 <- fn5(z), f6 <- fn6(z), f7 <- fn7(z), f8 <- fn8(z), replications = 2)

Результат:

          test replications elapsed  relative user.self sys.self
1 f1 <- fn1(z)            2   13.45 20.692308     13.27     0.15
2 f2 <- fn2(z)            2    3.54  5.446154      3.43     0.09
3 f3 <- fn3(z)            2    0.65  1.000000      0.54     0.10
4 f4 <- fn4(z)            2    3.62  5.569231      3.50     0.09
5 f5 <- fn5(z)            2   13.57 20.876923     13.25     0.25
6 f6 <- fn6(z)            2    3.53  5.430769      3.36     0.14
7 f7 <- fn7(z)            2    3.34  5.138462      3.28     0.03
8 f8 <- fn8(z)            2    3.34  5.138462      3.26     0.03
2 голосов
/ 25 октября 2011

Я бы использовал комбинацию ave и unique:

z <- data.frame(id=rep(c(1,1,2,2,3,4),1e5),var=rnorm(6e5))
z$var <- ave(z$var, z$id, FUN=mean)
z <- unique(z)

ОБНОВЛЕНИЕ: после фактического определения времени решения есть кое-что, что немного быстрее.

z <- data.frame(id=rep(c(1,1,2,2,3,4),1e5),var=rnorm(6e5))
system.time({
  averages <- t(sapply(split(z,z$id), function(x) sapply(x,mean)))
})
#    user  system elapsed 
#    1.32    0.00    1.33 
system.time({
  z$var <- ave(z$var, z$id, FUN=mean)
  z <- unique(z)
})
#    user  system elapsed 
#    4.33    0.02    4.37
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...