#r #apply
#r #применить
Вопрос:
Я новичок в R. Теперь у меня есть функция следующим образом:
funItemAverRating = function()
{
itemRatingNum = array(0, itemNum);
print("begin");
apply(input, 1, function(x)
{
itemId = x[2] 1;
itemAverRating[itemId] <<- itemAverRating[itemId] x[3];
itemRatingNum[itemId] <<- itemRatingNum[itemId] 1;
}
);
}
В этой функции вводом является n*3
фрейм данных, n
является ~6*(10e 7)
, itemRatingNum
является вектором размера ~3*(10e 5)
.
Мой вопрос в том, почему apply
функция работает так медленно (для завершения работы потребовался бы почти час)? Кроме того, по мере выполнения функции она использует все больше и больше памяти. Но, как вы можете видеть, все переменные определены вне apply
функции. Кто-нибудь может мне помочь?
ченг
Комментарии:
1. Трудно сказать, не видя, как выглядят данные (что такое
itemAverRating
, из каких столбцовinput
состоят), но я полагаю, вы могли бы сделать это безapply
использования векторизации. Например.:itemRatingNum[input[[2]] 1] <- itemRatingNum[input[[2]] 1] 1
2. Спасибо за ваш ответ. Есть ли какая-либо разница в эффективности между этим и функцией apply?
3. ДА. Работа с векторами, если намного, намного быстрее (может занять от 1 часа до <1 м)
4. @пользователь572138, пожалуйста, измените название вашего вопроса. Apply в целом работает не медленно, только по вашей конкретной причине, главным образом потому, что вы неправильно его используете.
5. @mpiktas Ок. Можете ли вы предоставить сценарий, в котором apply эффективно обрабатывает крупномасштабные данные (например, в моем случае)? Спасибо.
Ответ №1:
Это медленно, потому что вы вызываете высокоуровневые R-функции много раз.
Вы должны векторизовать свою функцию, что означает, что большинство операций (таких как <-
или 1
) должны вычисляться по всем векторам данных.
Например, мне кажется, что itemRatingNum
содержит частоты input[[2]]
(второй столбец input
data.frame
), которые можно было бы заменить на:
tb <- table(input[[2]] 1)
itemRatingNum[as.integer(names(tb))] <- tb
Комментарии:
1. Спасибо за ваш ответ. Но если я хочу сделать что-то вроде: itemPopu = tapply (ввод [,3], ввод [, 2], сумма); Есть ли какие-либо эффективные решения. Я обнаружил, что tapply выполняется очень медленно.
2. Попробуйте
rowsum(input[[3]],input[[2]])
Ответ №2:
Не делайте этого. Вы следуете логике, которая совершенно не похожа на R. Если я правильно понимаю, вы хотите добавить к определенному itemAverRating
вектору значение из третьего столбца в некотором входном фрейме данных.
То, что itemRatingNum
делается, довольно неясно. Это не попадает в глобальную среду, а просто становится вектором, заполненным частотами в конце цикла. Поскольку вы определяете itemRatingNum внутри функции, <<-
присваивание также назначит его в локальной среде функции, и оно будет уничтожено, когда функция завершится.
Далее вы должны ввести данные вашей функции и получить некоторый результат. Никогда не назначайте глобальную среду, если в этом нет необходимости. Ваша функция эквивалентна — скорее, намного быстрее — следующей функции, которая принимает входные данные и выдает выходные :
funItemAverRating = function(x,input){
sums <- rowsum(input[,3],input[,2])
sumid <- as.numeric(rownames(sums)) 1
x[sumid] c(sums)
}
ФУНКЦИЯ ОТРЕДАКТИРОВАНА СОГЛАСНО КОММЕНТАРИЮ МАРЕКСА
Который работает как :
# make data
itemNum <- 10
set.seed(12)
input <- data.frame(
a1 = rep(1:10,itemNum),
a2 = sample(9:0,itemNum*10,TRUE),
a3 = rep(10:1,itemNum)
)
itemAverRating <- array(0, itemNum)
itemAverRating <- funItemAverRating(itemAverRating,input)
itemAverRating
0 1 2 3 4 5 6 7 8 9
39 65 57 36 62 33 98 62 60 38
Если я попробую ваш код, я получу :
> funItemAverRating()
[1] "begin"
...
> itemAverRating
[1] 39 65 57 36 62 33 98 62 60 38
Что является тем же самым. Если вам нужен itemRatingNum, то просто сделайте :
> itemRatingNum <- table(input[,2])
0 1 2 3 4 5 6 7 8 9
6 11 11 8 10 6 18 9 13 8
Комментарии:
1. Я попробовал tapply, но обнаружил, что эта функция работает очень медленно, itemPopu = tapply(ввод[,3], ввод[,2], сумма); этот код отнял бы много времени. Есть ли какие-либо лучшие решения?
2. @user572138 : Это примерно в 13 раз быстрее, чем ваш код на моем компьютере, и он делает точно то же самое. Что вы подразумеваете под «медленным»?
3. В моих данных длина (входные данные) очень велика (~ 6 * 10e 7), но во входных данных много повторяющихся элементов [, 2]. Уникальный номер ввода [,2] равен ~ 3 * 10e5. Когда я запускаю tapply (ввод [,3], ввод [, 2], сумма), мне нужно долго ждать (по крайней мере, 5 минут). В C это, конечно, не будет стоить так долго.
4. Под «по крайней мере, 5 минут» я подразумеваю, что через 5 минут код все еще выполняется.
5. Номер строки ввода равен примерно (~ 6 * 10e 7).