根据常用值拆分列表

时间:2018-01-09 14:43:03

标签: r

我有一个包含数百个项目的列表,每个项目都有两个值,如下所示:

x <- list(c(123, 4), c(456, 4), c(124, 3), c(157, 3), c(123, 3), c(456, 3))

[[1]]
[1] 123   4

[[2]]
[1] 456   4

[[3]]
[1] 124   3

[[4]]
[1] 157   3

[[5]]
[1] 123   3

[[6]]
[1] 456   3

我想对这些数据做两件事:

1)根据常见的第二个值将其拆分为多个列表,给出:

> x1
[[1]]
[1] 123   4

[[2]]
[1] 456   4

> x2
[[1]]
[1] 124   3

[[2]]
[1] 157   3

[[3]]
[1] 456   3

[[4]]
[1] 123   3

2)根据第一个值将其合并到一个较短的列表中,给出:

> x3
[[1]]
[1] 123   3   4

[[2]]
[1] 456   3   4

[[3]]
[1] 124   3

[[4]]
[1] 157   3

我一直无法弄清楚如何做第二件事,我认为我想到的第一件事却不起作用:

y <- list()
for (i in 1:length(x)) {
  if(unique(x[[i]][2])){
# if(x[[i]][2] == 4){
    y[[length(y)+1]] <- x[[i]] }}

如果我使用unique()运行,那么y将返回与x相同的效果,这是不合适的。如果我使用散列线运行,那么我得到了正确的结果,但显然只适用于那些[[i]][2] == 4的情况。我认为unique()使用可能是错误的,但方向正确。知道该用什么呢?

4 个答案:

答案 0 :(得分:2)

我想你想要这个:

x1 <- split(x, sapply(x, function(x) x[[2]]))

和此:

x2 <- split(x, sapply(x, function(x) x[[1]]))
x2 <- lapply(x2, function(x) c(x[[1]][1], unique(sapply(x, function(y) y[[2]]))))

答案 1 :(得分:2)

这是一种使用&#34; data.table&#34;:

的方法
library(data.table)
data.table(do.call(rbind, x))[, list(new = list(c(V1, V2))), V1]$new
## [[1]]
## [1] 123   4   3
## 
## [[2]]
## [1] 456   4   3
## 
## [[3]]
## [1] 124   3
## 
## [[4]]
## [1] 157   3
## 

答案 2 :(得分:2)

如果你想将它严格保存在列表中,purrr很方便:

library(purrr)

x <- list(c(123, 4), c(456, 4), c(124, 3), c(157, 3), c(123, 3), c(456, 3))

x1 <- split(x, map_dbl(x, 2))

str(x1)
#> List of 2
#>  $ 3:List of 4
#>   ..$ : num [1:2] 124 3
#>   ..$ : num [1:2] 157 3
#>   ..$ : num [1:2] 123 3
#>   ..$ : num [1:2] 456 3
#>  $ 4:List of 2
#>   ..$ : num [1:2] 123 4
#>   ..$ : num [1:2] 456 4

x2 <- x %>% 
    split(map_dbl(., 1)) %>% 
    modify_depth(2, ~.x[-1]) %>% 
    simplify_all() %>% 
    imap(~c(as.integer(.y), .x))

str(x2)
#> List of 4
#>  $ 123: num [1:3] 123 4 3
#>  $ 124: num [1:2] 124 3
#>  $ 157: num [1:2] 157 3
#>  $ 456: num [1:3] 456 4 3

可能更有用的是,purrr可以快速将列表转换为整洁的数据框,以便您可以通过分组操作完成这些任务:

df_x <- x %>% map_dfr(~list(x = .x[1], y = .x[2]))
# or equivalent but more programmatic,
df_x <- x %>% map_dfr(compose(as.list, set_names), c('x', 'y'))

df_x
#> # A tibble: 6 x 2
#>       x     y
#>   <dbl> <dbl>
#> 1   123  4.00
#> 2   456  4.00
#> 3   124  3.00
#> 4   157  3.00
#> 5   123  3.00
#> 6   456  3.00

通过dplyr::group_bysummarisetidyr::nest或您有什么。

答案 3 :(得分:1)

我建议将数据整形为data.frame(或tidyverse tibble)

library(tidyverse)
x = list(c(123, 4), c(456, 4), c(124, 3), c(157, 3), c(123, 3), c(456, 3))
first = vapply(x, `[[`, numeric(1), 1)
second = vapply(x, `[[`, numeric(1), 2)
elt = seq_along(x)
tbl = tibble(elt = elt, first = first, second = second)

并对此进行操作,或许重新考虑是否需要'单独列表'等。例如,group_by()强制分组,summarize()形成包含第二个元素列表的列

tbl %>% group_by(first) %>% summarize(values=list(second))

...但是,summarize()语句创建的列表列现在在后续工作流程中是多余的?例如,按组分列的计数和均值为summarize(n = n(), mean = mean(second))