【问题标题】:R, dpylr: Converting list of lists of differing lenghts within dataframe into long format dataframeR,dplyr:将数据帧内不同长度的列表转换为长格式数据帧
【发布时间】:2017-06-01 17:06:15
【问题描述】:

我正在为以下任务寻找 dplyr-ish 解决方案。我有一个数据框,其中包含一个变量,该变量是具有属性 dimnames 的列表列表。这些列表具有不同的长度。这是str(df)的输出:

Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   3 obs. of  2 variables:
 $ Step : int  1 2 3
 $ Value:List of 3
  ..$ : num [1:2, 1:2] 0.232 0.261 0.932 0.875
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : chr  "4" "5"
  .. .. ..$ : chr  "0.2" "0.094"
  ..$ : num [1:2, 1:5] 0.197 0.197 0.64 0.643 0.958 ...
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : chr  "4" "5"
  .. .. ..$ : chr  "0.2" "0.094" "0.044" "0.021" ...
  ..$ : num [1:2, 1] 0.268 0.262
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : chr  "4" "5"
  .. .. ..$ : chr "0.2"

我在下面包含了 dput 代码来重新创建这个数据框。

我想要以下格式的数据框:

Step    Value   a     b
 1      0.232   4   0.200
 1      0.261   5   0.200
 1      0.932   4   0.094
 1      0.875   5   0.094
 1       NA     4   0.044
 1       NA     5   0.044
 1       NA     4   0.021
 1       NA     5   0.021
 1       NA     4   0.010
 1       NA     5   0.010
 2      0.197   4   0.200
 2      0.197   5   0.200
 2      0.640   4   0.094
 2      0.643   5   0.094
 2      0.958   4   0.044
 2      1.032   5   0.044
 2      0.943   4   0.021
 2      1.119   5   0.021
 2      0.943   4   0.010
 2      1.119   5   0.010
 3      0.268   4   0.200
 3      0.262   5   0.200
 3       NA     4   0.094
 3       NA     5   0.094
 3       NA     4   0.044
 3       NA     5   0.044
 3       NA     4   0.021
 3       NA     5   0.021
 3       NA     4   0.010
 3       NA     5   0.010

其中变量a 是dimnames 列表的行名,b 是列名。

我尝试了一个for 循环来逐步分离每个列表,但是

1) 我没有成功用NAs 填充列表(length(x) <- y 不起作用)。

2) 我已经查看了 advanced R data types,但未能成功将 dimnames 提取到向量中以用作数据框列(attr(df$Value, "dimnames") 产生 NULL。)

一旦我有了相同长度的列表,我就可以在for 循环中逐步构建新的数据帧向量,然后再进行 rbind。或者有没有办法使用 dimname 属性直接使用行和列的暗名作为数据框列名来构建宽数据框?然后我可以gather 制作一个长数据框。

这里有几个子问题,我确信有一个比我制定的解决方案更优雅的解决方案。感谢观看。

这是创建数据框的 dput 代码:

df <- structure(list(Step = c(1L, 2L, 3L), Value = list(structure(c(0.232, 
0.261, 0.932, 0.875), .Dim = c(2L, 
2L), .Dimnames = list(c("4", "5"), c("0.2", "0.094"
))), structure(c(0.197, 0.197, 0.640, 
0.643, 0.958, 1.032, 0.943, 
1.119, 0.943, 1.119), .Dim = c(2L, 
5L), .Dimnames = list(c("4", "5"), c("0.2", "0.094", 
"0.044", "0.021", "0.01"))), structure(c(0.268, 
0.262), .Dim = c(2L, 1L), .Dimnames = list(c("4", 
"5"), "0.2")))), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
-3L), .Names = c("Step", "Value"))

【问题讨论】:

  • 看起来该变量是矩阵列表,而不是列表列表?
  • 可能是,str(df$Value[[1]]) 产生 num [1:2, 1:2] 0.232 0.261 0.932 0.875 - attr(*, "dimnames")=List of 2 ..$ : chr [1:2] "4" "5" ..$ : chr [1:2] "0.2" "0.094",但不是矩阵,是具有维度属性的列表,我仍然需要使用 dimnames 作为变量转换为长数据框。我想不出办法来解开这个物体。
  • 是的,num [1:2, 1:2] 表示二维数值数组,即矩阵。只有 dimnames 是一个列表。

标签: r dataframe dplyr


【解决方案1】:

方法一:

首先,我们将矩阵添加到 data.frames,然后将行名添加为名为 a 的单独列,并将它们全部收集起来。通过取消嵌套,我们得到一个大数据框架。使用complete 添加NA 值很容易

library(tidyverse) # using dplyr, tidyr and purrr

df %>% 
  mutate(Value = map(Value, as.data.frame),
         Value = map(Value, rownames_to_column, 'a'),
         Value = map(Value, ~gather(., b, value, -a))) %>% 
  unnest(Value) %>% 
  complete(Step, a, b)

方法二:

手动定义data.frame,然后做同样的事情:

df %>% 
  mutate(Value = map(Value, 
                     ~data_frame(val = c(.), 
                                 a = rep(rownames(.), each = ncol(.)),
                                 b = rep(colnames(.), nrow(.))))) %>% 
  unnest(Value) %>% 
  complete(Step, a, b))

结果:

两者都给出:

# A tibble: 30 × 4
    Step     a     b value
   <int> <chr> <chr> <dbl>
1      1     4  0.01    NA
2      1     4 0.021    NA
3      1     4 0.044    NA
4      1     4 0.094 0.932
5      1     4   0.2 0.232
6      1     5  0.01    NA
7      1     5 0.021    NA
8      1     5 0.044    NA
9      1     5 0.094 0.875
10     1     5   0.2 0.261
# ... with 20 more rows

【讨论】:

  • 我无语了,这么快,不是一个,而是两个选择。让我玩这些,我会回复你的。我确定我会有问题。
  • 做到了,而且我的真实数据框很快。我不知道这会这么容易,而且我已经学会了几个漂亮的技巧。我已经使用 map 和函数,但之前没有使用 value 设置,而且我还没有看到完整的。 〜做什么?
  • 这是在purrr中定义匿名函数的方法之一。请参阅?map.f 参数。
【解决方案2】:

不是真正的dplyr 解决方案,但您可以这样做:

## Get the maximum length in l$Value and the index where it is observed
m = max(lengths(l$Value))
[1] 10
j = which.max(lengths(l$Value))
[1] 2

然后为l$Valuerbind它们的每个元素构造一个dataframe并添加Step列:

l2 = lapply(l$Value,function(x) data.frame(a=rep(row.names(x),length.out=m),
Value=x[1:m],b=rep(colnames(l$Value[[j]]),length.out=m)))
df = do.call(rbind,l2)
df$Step = rep(l$Step,each=m)

这会返回:

   a Value     b Step
1  4 0.232   0.2    1
2  5 0.261 0.094    1
3  4 0.932 0.044    1
4  5 0.875 0.021    1
5  4    NA  0.01    1
6  5    NA   0.2    1
7  4    NA 0.094    1
8  5    NA 0.044    1
9  4    NA 0.021    1
10 5    NA  0.01    1
11 4 0.197   0.2    2
12 5 0.197 0.094    2
13 4 0.640 0.044    2
14 5 0.643 0.021    2
15 4 0.958  0.01    2
16 5 1.032   0.2    2
17 4 0.943 0.094    2
18 5 1.119 0.044    2
19 4 0.943 0.021    2
20 5 1.119  0.01    2
21 4 0.268   0.2    3
22 5 0.262 0.094    3
23 4    NA 0.044    3
24 5    NA 0.021    3
25 4    NA  0.01    3
26 5    NA   0.2    3
27 4    NA 0.094    3
28 5    NA 0.044    3
29 4    NA 0.021    3
30 5    NA  0.01    3

【讨论】:

    猜你喜欢
    • 2018-11-18
    • 2019-04-13
    • 2022-01-04
    • 1970-01-01
    • 2020-09-09
    • 2013-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多