Функция apply () не работает на отдельных строках - PullRequest
0 голосов
/ 26 мая 2019

Я написал функцию для извлечения данных из большой матрицы ("c.mat") для каждой строки в data.frame ("df.1").В data.frame есть строка индексации («df.1 $ hour»), которая соответствует соответствующему столбцу в матрице.Между матрицей и data.frame имеется одинаковое количество строк, поэтому функция выглядит так:

assignUV.FUN <- function(df, mat){
  num=df$hour
  value = mat[as.numeric(rownames(df)),num]
  return(value)
}

Довольно просто.Однако при использовании apply для запуска каждой строки:

df.1 <- data.frame(hour= round(runif(10,1,100)), x = seq(1,10, length=10))
c.mat <- matrix(runif(1000,1,5), nrow=10)

try <- apply(df.1, 1, assignUV.FUN, mat = c.mat, df=df.1)

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

Error in FUN(newX[, i], ...) : unused argument (newX[, i])

Я уверен, что здесь возникает конфликт, из-за которого я вызываю данные.кадр дважды, один раз изнутри функции assignUV.FUN и один раз с apply, но я не могу понять, почему это не сработает.

Есть мысли?Работает нормально, если я просто запускаю одну строку:

assignUV.FUN(df = df.1[1,], mat=c.mat)

Ответы [ 2 ]

3 голосов
/ 26 мая 2019

Если я вас правильно понял, вы хотите установить подмножество c.mat для каждой строки в df.1 на основе значения в столбце hour. Я не думаю, что apply - лучший выбор здесь, так как вы хотите установить его под индексом строки и столбца. apply передает значение строки, а не ее индекс, который вам нужен для поднабора. Один вариант из семейства apply - использовать mapply

mapply(function(x, y) c.mat[x, y], seq_len(nrow(df.1)), df.1$hour)
#[1] 2.472 3.980 3.654 4.868 4.204 3.320 4.191 3.296 1.016 4.353

Или векторизованный подход будет

c.mat[cbind(1:nrow(df.1), df.1$hour)]
#[1] 2.472 3.980 3.654 4.868 4.204 3.320 4.191 3.296 1.016 4.353

Чтобы узнать подробнее, почему это работает, когда вы подаете заявку на одну строку индивидуально, а не когда вы используете apply, обратите внимание, когда вы задаете одну строку, это все еще один кадр данных с заголовком.

df.1[1, ]
#  hour x
#1   31 1

class(df.1[1, ])
#[1] "data.frame"

Поэтому, когда вы выполните df$hour в функции assignUV.FUN, вы получите значение

df.1[1, ]$hour
#[1] 31

Однако это не относится к apply

apply(df.1[1, ], 1, class)
#        1 
#"numeric" 

и если вы попытаетесь извлечь значение

apply(df.1[1, ], 1, function(x) x$hour)

Ошибка в x $ hour: оператор $ недопустим для атомных векторов

Вы можете решить вышеупомянутую проблему, используя позицию вместо имени, выполнив

apply(df.1[1, ], 1, function(x) x[1])
#31 

но это дает вам столбец для подмножества из c.mat, а не строку.

данные

set.seed(100)
df.1 <- data.frame(hour= round(runif(10,1,100)), x = seq(1,10, length=10))
c.mat <- matrix(runif(1000,1,5), nrow=10)
1 голос
/ 26 мая 2019

Векторный подход Ронака - путь, но я надеюсь, что это может быть поучительно. apply не передает data.frame в FUN, но вместо вектора, так что вы можете попробовать,

assignUV.FUN <- function(DF, mat){
  num=DF[1]
  value = mat[DF[2],num]
  return(value)
}

try <- apply(df.1, 1, assignUV.FUN, mat = c.mat)

Нет необходимости передавать все аргументы FUN в apply, я только передал c.mat, так как он не «зацикливается». Также я стараюсь избегать именования data.frame s df, поскольку R уже имеет функцию с именем df (плотность распределения F).

...