Заполнение кадра данных в R в цикле
Я пытаюсь заполнить фрейм данных из цикла for в R. Названия столбцов генерируются динамически в цикле, а значение некоторых из переменных цикла используется как значения при заполнении кадра данных. Например, имя текущего столбца может быть некоторым именем переменной в виде строки в цикле, а столбец может принимать значение текущего итератора как его значение в кадре данных.
Я попытался создать пустой цикл данных за пределами цикла, как этот
d = data.frame()
Но я не могу ничего с этим поделать, как только я попытаюсь заполнить его, я столкнулся с ошибкой
d[1] = c(1,2)
Error in `[<-.data.frame`(`*tmp*`, 1, value = c(1, 2)) :
replacement has 2 rows, data has 0
Что может быть хорошим способом добиться того, что я ищу. Пожалуйста, дайте мне знать, если я не поняла.
Ответы
Ответ 1
Вы можете сделать это следующим образом:
iterations = 10
variables = 2
output <- matrix(ncol=variables, nrow=iterations)
for(i in 1:iterations){
output[i,] <- runif(2)
}
output
а затем превратите его в data.frame
output <- data.frame(output)
class(output)
что это делает:
- создать матрицу со строками и столбцами в соответствии с ожидаемым ростом
- вставить 2 случайных числа в матрицу
- преобразуйте это в кадр данных после завершения цикла.
Ответ 2
Часто предпочтительнее избегать циклов и использовать векторизованные функции. Если это невозможно, существует два подхода:
- Предоставить выделение
data.frame
. Это не рекомендуется, поскольку индексирование выполняется медленно для data.frames
.
- Используйте другую структуру данных в цикле и затем преобразуйте ее в
data.frame
. A list
здесь очень полезен.
Пример, иллюстрирующий общий подход:
mylist <- list() #create an empty list
for (i in 1:5) {
vec <- numeric(5) #preallocate a numeric vector
for (j in 1:5) { #fill the vector
vec[j] <- i^j
}
mylist[[i]] <- vec #put all vectors in the list
}
df <- do.call("rbind",mylist) #combine all vectors into a matrix
В этом примере нет необходимости использовать list
, вы можете предварительно выделить matrix
. Однако, если вы не знаете, сколько итераций потребуется вашему циклу, вы должны использовать list
.
Наконец, это векторная альтернатива примеру цикла:
outer(1:5,1:5,function(i,j) i^j)
Как вы видите, это проще и эффективнее.
Ответ 3
У меня был случай, когда мне нужно было использовать фрейм данных внутри функции цикла. В этом случае это был "эффективный", однако имейте в виду, что база данных была небольшой, и итерации в цикле были очень простыми. Но, возможно, код может быть полезен для кого-то с аналогичными условиями.
Целью цикла было использование функции извлечения растра вдоль пяти местоположений (т.е. 5 Токио, Нью-Йорк, Сау-Паулу, Сеул и Мехико), и каждое место имело свои растровые решетки. У меня была база данных пространственных точек с более чем 1000 наблюдениями, выделенными в 5 разных местах, и мне нужно было извлечь информацию из 10 различных растровых сеток (две сетки на каждое место). Кроме того, для последующего анализа мне требовались не только значения растра, но и уникальный идентификатор для каждого наблюдения.
После подготовки пространственных данных, которые включали следующие задачи:
- Импорт точек шейп файла с помощью функции readOGR (пакет rgdap)
- Импортировать растровые файлы с помощью растровой функции (растровый пакет)
- Решетки стека из одного и того же местоположения в один файл с помощью стека функций (растровый пакет)
Здесь код цикла цикла с использованием кадра данных:
1. Добавьте штабелированные растры на каждое место в список
raslist <- list(LOC1,LOC2,LOC3,LOC4,LOC5)
2. Создайте пустой фреймворк данных, это будет выходной файл
TB <- data.frame(VAR1=double(),VAR2=double(),ID=character())
3. Настройка для функции цикла
L1 <- seq(1,5,1) # the location ID is a numeric variable with values from 1 to 5
for (i in 1:length(L1)) {
dat=subset(points,LOCATION==i) # select corresponding points for location [i]
t=data.frame(extract(raslist[[i]],dat),dat$ID) # run extract function with points & raster stack for location [i]
names(t)=c("VAR1","VAR2","ID")
TB=rbind(TB,t)
}