简体   繁体   中英

Creating a dataframe of unequal length list in R

I'm currently running into the issue of creating a dataframe of an unequal length list. The issue I have is that there are corresponding categorical data to each list I have.

This is what I have so far

#Extract raster values to polygons 
v <- extract(burnclass, ws_proj2)  
v

#Get class counts for each polygon depending on the number of polygons

v.counts <- lapply(v,table)
v.counts

Result

[[1]]

  1   2   3   4   5   6   7 
 17  81 210 127  83  59 172 

[[2]]

  3   4   5   6   7 
660 796 612 647 348 

[[3]]

  3   4   5   6   7 
 11  55  76  98 323 

[[4]]

 -1   1   2   3   4   5   6   7 
963 229 173 136 114  97 111 322 

[[5]]

   3    4    5    6    7 
 664  289  192  526 1122 

[[6]]

  3   4   5   6   7 
450 386 158 125 144 

[[7]]

  -1    3    4    5    6    7 
5392  104  391  557 1221  885 

I've tried the code below, to create a dataframe but the outcome attaches NA values to the end of each string and it is not what I need.

res <- as.data.frame(do.call(rbind,lapply(v.counts, `length<-`,max(indx))))

colnames(res) <- names(v.counts[[which.max(indx)]])
res

Result

在此处输入图像描述

The solution I'm looking for is this

在此处输入图像描述

I would appreciate any help with this!

A purrr solution

library(purrr)
map_dfr(v.counts, ~.x)[order(as.numeric(names(map_dfr(v.counts, ~.x))))]
#> # A tibble: 7 x 8
#>    `-1`   `1`   `2`   `3`   `4`   `5`   `6`   `7`
#>   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1    NA    17    81   210   127    83    59   172
#> 2    NA    NA    NA   660   796   612   647   348
#> 3    NA    NA    NA    11    55    76    98   323
#> 4   963   229   173   136   114    97   111   322
#> 5    NA    NA    NA   664   289   192   526  1122
#> 6    NA    NA    NA   450   386   158   125   144
#> 7  5392    NA    NA   104   391   557  1221   885

Since you haven't provided any dput, I have created v.counts as

v.counts <- list(c(`1` = 17, `2` = 81, `3` = 210, `4` = 127, `5` = 83, `6` = 59, `7` = 172),
     c(`3` = 660, `4` = 796, `5` = 612, `6` = 647, `7` = 348),
     c(`3` = 11, `4` = 55, `5` = 76, `6` = 98, `7` = 323),
     c(`-1` = 963, `1` =229, `2` = 173, `3` = 136, `4` = 114, `5` = 97, `6` = 111, `7` = 322),
     c(`3` = 664, `4` = 289, `5` = 192, `6` = 526, `7` = 1122),
     c(`3` = 450, `4` = 386, `5` = 158, `6` = 125, `7` = 144),
     c(`-1` = 5392,`3` = 104, `4` = 391, `5` = 557, `6` = 1221, `7` = 885))

v.counts
#> [[1]]
#>   1   2   3   4   5   6   7 
#>  17  81 210 127  83  59 172 
#> 
#> [[2]]
#>   3   4   5   6   7 
#> 660 796 612 647 348 
#> 
#> [[3]]
#>   3   4   5   6   7 
#>  11  55  76  98 323 
#> 
#> [[4]]
#>  -1   1   2   3   4   5   6   7 
#> 963 229 173 136 114  97 111 322 
#> 
#> [[5]]
#>    3    4    5    6    7 
#>  664  289  192  526 1122 
#> 
#> [[6]]
#>   3   4   5   6   7 
#> 450 386 158 125 144 
#> 
#> [[7]]
#>   -1    3    4    5    6    7 
#> 5392  104  391  557 1221  885

Created on 2021-06-07 by the reprex package (v2.0.0)

Here is a base R option using Reduce + merge + as.list (thank @AnilGoyal's data)

res <- Reduce(
  function(x, y) merge(x, y, all = TRUE),
  Map(function(k, v) data.frame(c(id = k, as.list(v))), seq_along(v.counts), v.counts)
)

res[order(names(res))][res$id, ]

which gives

  id  X.1  X1  X2  X3  X4  X5   X6   X7
1  1   NA  17  81 210 127  83   59  172
2  2   NA  NA  NA 660 796 612  647  348
3  3   NA  NA  NA  11  55  76   98  323
4  4  963 229 173 136 114  97  111  322
5  5   NA  NA  NA 664 289 192  526 1122
6  6   NA  NA  NA 450 386 158  125  144
7  7 5392  NA  NA 104 391 557 1221  885

I think you can also use this simple solution, using @AnikGoyal's sample data:

library(dplyr)

v.counts %>% bind_rows() %>% select(sort(names(.)))

# A tibble: 7 x 8
   `-1`   `1`   `2`   `3`   `4`   `5`   `6`   `7`
  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1    NA    17    81   210   127    83    59   172
2    NA    NA    NA   660   796   612   647   348
3    NA    NA    NA    11    55    76    98   323
4   963   229   173   136   114    97   111   322
5    NA    NA    NA   664   289   192   526  1122
6    NA    NA    NA   450   386   158   125   144
7  5392    NA    NA   104   391   557  1221   885

You could do:

  levs <- unique(unlist(v))
  t(sapply(v, function(x) table(factor(x, levs))))
       1   2   3   4   5    6    7   -1
[1,]  17  81 210 127  83   59  172    0
[2,]   0   0 660 796 612  647  348    0
[3,]   0   0  11  55  76   98  323    0
[4,] 229 173 136 114  97  111  322  963
[5,]   0   0 664 289 192  526 1122    0
[6,]   0   0 450 386 158  125  144    0
[7,]   0   0 104 391 557 1221  885 5392

A data.table approach, using the sample data provided in the answer from AnilGoyal.

library(data.table)
# Create a list of data.tables from the named vectors
L <- lapply(v.counts, function(x) data.table(names = names(x), x))
# rowbind list and cast to wide format
dcast(rbindlist(L, idcol = "id"), id ~ names, value.var = "x", fill = NA)
#    id   -1   1   2   3   4   5    6    7
# 1:  1   NA  17  81 210 127  83   59  172
# 2:  2   NA  NA  NA 660 796 612  647  348
# 3:  3   NA  NA  NA  11  55  76   98  323
# 4:  4  963 229 173 136 114  97  111  322
# 5:  5   NA  NA  NA 664 289 192  526 1122
# 6:  6   NA  NA  NA 450 386 158  125  144
# 7:  7 5392  NA  NA 104 391 557 1221  885

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM