Использование цикла for для заполнения матрицы при выполнении условий столбца в R - PullRequest
0 голосов
/ 19 октября 2018

Я изучаю R для экологического исследования и пытаюсь написать функцию для создания нескольких матриц.

Мой фрейм данных выглядит так:

df <- data.frame(Species = c("a", "b", "c", "a", "d", "a", "b", "c", "c", "a", "c", "b", "e"),
             Count = c(2, 3, 1, 3, 4, 1, 2, 1, 1, 3, 2, 4, 1),
             Haul = c(1, 1, 2, 2, 1, 3, 2, 3, 4, 1, 1, 2, 1),
             Year = c(2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2001, 2001, 2001, 2001))

Напечатано:

Species Count Haul Year
1        a     2    1 2000
2        b     3    1 2000
3        c     1    2 2000
4        a     3    2 2000
5        d     4    1 2000
6        a     1    3 2000
7        b     2    2 2000
8        c     1    3 2000
9        c     1    4 2000
10       a     3    1 2001
11       c     2    1 2001
12       b     4    2 2001
13       e     1    1 2001

Я хочу создать цикл for, который будет генерировать и хранить матрицы в списке.Эти матрицы будут основываться на улове и видах в каждом году.

Например, я пытался что-то вроде.

for (i in sort(unique(df$Year))) {
ncol <- sort(unique(unlist(df$Species)))
nrow <- sort(unique(unlist(subset(df, Year == i, select=c("Haul")))))
mat <- matrix(0, length(nrow), length(ncol),
              dimnames = list(nrow, ncol))
mat[as.matrix(df[c("Haul", "Species")])] <- df$Count

Это не помогло.

Я ищу решение, подобное

list[[1]]
[["2000"]] a  b  c  d  e
         1 2  3  0  4  0
         2 3  2  1  0  0
         3 1  0  1  0  0
         4 0  0  1  0  0

[["2001"]] a  b  c  d  e 
         1 3  0  2  0  1  
         2 0  4  0  0  0

цель состоит в том, чтобы столбцы представляли собой общее количество когда-либо замеченных видов, а строки - конкретные выборки за год.Затем цикл for будет складывать матрицы в список.

Главное, что я попробовал, это создать обнуленную матрицу и попытаться заполнить данные функцией mat[as.matrix()], но я получаю ошибку subscript out of bound.

Я перепробовал много методов, но я только учусь на том, что я могу найти в Интернете.Любая помощь будет принята с благодарностью.Спасибо!

Ответы [ 3 ]

0 голосов
/ 19 октября 2018

В этом предложении используется tidyr::spread, хотя это возможно сделать в базе R, используя reshape.

out <- by(df, df$Year, function(a) tidyr::spread(a, Species, Count, fill=0))
out
# df$Year: 2000
#   Haul Year a b c d
# 1    1 2000 2 3 0 4
# 2    2 2000 3 2 1 0
# 3    3 2000 1 0 1 0
# 4    4 2000 0 0 1 0
# -------------------------------------------------------------------------------------------- 
# df$Year: 2001
#   Haul Year a b c e
# 1    1 2001 3 0 2 1
# 2    2 2001 0 4 0 0

Технически, вывод равен

class(out)
# [1] "by"

, но это простопрославленный способ обеспечить by -подобную печать.Чтобы проверить:

str(out)
# List of 2
#  $ 2000:'data.frame': 4 obs. of  6 variables:
#   ..$ Haul: num [1:4] 1 2 3 4
#   ..$ Year: num [1:4] 2000 2000 2000 2000
#   ..$ a   : num [1:4] 2 3 1 0
#   ..$ b   : num [1:4] 3 2 0 0
#   ..$ c   : num [1:4] 0 1 1 1
#   ..$ d   : num [1:4] 4 0 0 0
#  $ 2001:'data.frame': 2 obs. of  6 variables:
#   ..$ Haul: num [1:2] 1 2
#   ..$ Year: num [1:2] 2001 2001
#   ..$ a   : num [1:2] 3 0
#   ..$ b   : num [1:2] 0 4
#   ..$ c   : num [1:2] 2 0
#   ..$ e   : num [1:2] 1 0
#  - attr(*, "dim")= int 2
#  - attr(*, "dimnames")=List of 1
#   ..$ df$Year: chr [1:2] "2000" "2001"
#  - attr(*, "call")= language by.data.frame(data = df, INDICES = df$Year, FUN = function(a) tidyr::spread(a, Species, Count, fill = 0))
#  - attr(*, "class")= chr "by"

Таким образом, мы можем просто переопределить класс с помощью

class(out) <- "list"
out
# $`2000`
#   Haul Year a b c d
# 1    1 2000 2 3 0 4
# 2    2 2000 3 2 1 0
# 3    3 2000 1 0 1 0
# 4    4 2000 0 0 1 0
# $`2001`
#   Haul Year a b c e
# 1    1 2001 3 0 2 1
# 2    2 2001 0 4 0 0
# attr(,"call")
# by.data.frame(data = df, INDICES = df$Year, FUN = function(a) tidyr::spread(a, 
#     Species, Count, fill = 0))

Я сохранил Year там для простоты и демонстрации (на случай, если вы захотите сохранить егопо какой-то причине), но это так же легко удалить с помощью:

out <- by(df, df$Year, function(a) tidyr::spread(subset(a, select=-Year), Species, Count, fill=0))

(Поскольку я уже ввел один из tidyverse с tidyr, я мог бы легко использовать dplyr::select(a, -Year) instead of thesubset` call. Вам и любым используемым вами инструментам.)

Теперь я признаю, что это производит data.frame s, а не матрицы.Потребовалось бы немного больше кода, чтобы преобразовать результат для каждого в правильную матрицу.

df2m <- function(x) {
  # assume first column should be row names
  rn <- x[[1]]
  out <- as.matrix(x[-1])
  rownames(out) <- rn
  out
}
lapply(out, df2m)
# $`2000`
#   a b c d
# 1 2 3 0 4
# 2 3 2 1 0
# 3 1 0 1 0
# 4 0 0 1 0
# $`2001`
#   a b c e
# 1 3 0 2 1
# 2 0 4 0 0
0 голосов
/ 19 октября 2018

Рассмотрим by (функция для разделения кадров данных по фактору (ам) для запуска процессов на подмножествах) и table (функция для построения таблицы непредвиденных обстоятельств по комбинациям факторов).Конечным результатом является именованный список матриц.

matrix_list <- by(df, df$Year, function(sub) {    
    mat <- table(sub$Haul, sub$Species)
    mat[as.matrix(sub[c("Haul", "Species")])] <- sub$Count

    return(mat)      
})

matrix_list$`2000`

#   a b c d e
# 1 2 3 0 4 0
# 2 3 2 1 0 0
# 3 1 0 1 0 0
# 4 0 0 1 0 0

matrix_list$`2001`

#   a b c d e
# 1 3 0 2 0 1
# 2 0 4 0 0 0
0 голосов
/ 19 октября 2018

Мне не понятно, почему вы хотите сделать это в виде списка матриц, особенно если ваши исходные данные уже аккуратные .Если вы просто хотите трансформировать данные из длинных в широкие по видам, это следует сделать.

library(tidyverse)

df %>% 
  #spread Species from long to wide data
  spread(key = Species, value = Count, fill = 0) %>% 
  #Make Year the first column
  select(Year, everything()) %>% 
  #sort by Year and Haul
  arrange(Year, Haul)

Year Haul a b c d e
2000    1 2 3 0 4 0
2000    2 3 2 1 0 0
2000    3 1 0 1 0 0
2000    4 0 0 1 0 0
2001    1 3 0 2 0 1
2001    2 0 4 0 0 0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...