Как улучшить этот алгоритм? - PullRequest
5 голосов
/ 13 апреля 2011

R Версия 2.11.1 32-разрядная в Windows 7

Я получаю данные train.txt, как показано ниже:

USER_A USER_B ACTION
1        7      0
1        8      1
2        6      2
2        7      1
3        8      2

И я работаю с данными, как алгоритм ниже:

train_data=read.table("train.txt",header=T)
result=matrix(0,length(unique(train_data$USER_B)),2)
result[,1]=unique(train_data$USER_B)
for(i in 1:dim(result)[1])
{
    temp=train_data[train_data$USER_B%in%result[i,1],]
    result[i,2]=sum(temp[,3])/dim(temp)[1]
}

результат - оценка каждого USER_B в train_data.оценка определяется как:

оценка USER_B = (сумма всех ДЕЙСТВИЙ USER_B) / (рекомендуемое время USER_B)

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

Ответы [ 4 ]

6 голосов
/ 13 апреля 2011

Используя ваш пример, вы хотите рассчитать среднее действие для каждого уникального пользователя USER_B:

     [,1] [,2]
[1,]    7  0.5
[2,]    8  1.0
[3,]    6  2.0

Это можно сделать с помощью одной строки кода, используя функцию ddply() в пакете plyr

library(plyr)
ddply(train_data[, -1], .(USER_B), numcolwise(mean))

  USER_B ACTION
1      6    2.0
2      7    0.5
3      8    1.0

В качестве альтернативы функция tapply в базе R делает то же самое:

tapply(train_data$ACTION, train_data$USER_B, mean)

В зависимости от размера вашей таблицы вы можете улучшить время выполнения в 20 разили выше.Вот тест system.time для data.frame с миллионом записей.Ваш алгоритм занимает 116 секунд, ddply () занимает 5,4 секунды, а tapply - 1,2 секунды:

train_data <- data.frame(
        USER_A = 1:1e6,
        USER_B = sample(1:1e3, size=1e6, replace=TRUE),
        ACTION = sample (1:100, size=1e6, replace=TRUE))

yourfunction <- function(){
    result <- matrix(0,length(unique(train_data$USER_B)),2)
    result[,1] <- unique(train_data$USER_B);
    for(i in 1:dim(result)[1]){     
        temp=train_data[train_data$USER_B%in%result[i,1],]
        result[i,2]=sum(temp[,3])/dim(temp)[1]
    }
    result
}

system.time(XX <- yourfunction())
   user  system elapsed 
 116.29   14.04  134.33 

system.time(YY <- ddply(train_data[, -1], .(USER_B), numcolwise(mean)))
   user  system elapsed 
   5.43    1.60    7.19 

system.time(ZZ <- tapply(train_data$ACTION, train_data$USER_B, mean))
   user  system elapsed 
   1.17    0.06    1.25 
5 голосов
/ 13 апреля 2011

В дополнение к подходам, предоставляемым @Andrie, подход split() затем lapply() еще быстрее:

> system.time(ZZ <- tapply(train_data$ACTION, train_data$USER_B, mean))
   user  system elapsed 
  1.025   0.011   1.062 
> system.time(WW <- unlist(lapply(split(train_data$ACTION, 
+                                       f = train_data$USER_B), 
+                          mean)))
   user  system elapsed 
  0.465   0.007   0.483

sapply() также быстро справляется с этой проблемой:

> system.time(SS <- sapply(split(train_data$ACTION, f = train_data$USER_B), 
+                          mean))
   user  system elapsed 
  0.469   0.001   0.474
4 голосов
/ 05 мая 2011

@ gavin уже продемонстрировал высокую производительность при использовании комбинации split и lapply.

Пакет data.table предлагает дальнейшее заметное увеличение производительности на ~ 75%

library(data.table)
system.time({
      VV <- as.data.table(train_data)[, list(ACTION=mean(ACTION)), by=USER_B]
    })

user  system elapsed 
0.15    0.02    0.17 

system.time(WW <- unlist(lapply(split(train_data$ACTION, f = train_data$USER_B),mean)))

user  system elapsed 
0.61    0.02    0.63 

all(WW==VV$ACTION)
[1] TRUE

Пакет data.table доступен на CRAN и имеет веб-сайт на r-forge

0 голосов
/ 13 апреля 2011

Вы можете попробовать на tapply:

train_data <- read.table("train.txt",header=T);
result <- tapply(train_data$ACTION,train_data$USER_B,function(x) sum(x)/length(x)); 

Вы можете использовать mean вместо function.., но я недавно прочитал, что это последнее решение быстрее (если у вас нетлюбые NA с и т. д.).

Я не проверял, но считаю, что это должно быть быстрее.Если вам нужно еще более быстрое решение, взгляните на пакеты Rcpp и inline ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...