R,dpylr:将数据帧内不同长度的列表列表转换为长格式数据帧

时间:2017-06-01 17:06:16

标签: r dataframe dplyr

我正在为以下任务寻求一个解决方案。我有一个数据框,其中包含一个变量,该变量是具有属性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)我没有成功填写NA s(length(x) <- y无效)列表。

2)我已经审核了advanced R data types,但未成功将dimnames提取到矢量中以用作数据帧列(attr(df$Value, "dimnames")会产生NULL。)< / p>

一旦我有相同长度的列表,我就可以在for循环中逐步构建新的数据帧向量,然后再建立rbind。或者有没有办法使用dimname属性直接构造一个宽的数据帧使用行和列dimnames作为数据帧列名?然后我可以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"))

2 个答案:

答案 0 :(得分:1)

方法一:

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

可轻松添加complete
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

答案 1 :(得分:1)

不是真正的INSERT INTO HOTELTABLE(HOTEL_CHAIN,HOTEL_LOCATION,HOTEL_OWNER) select distinct f1.HOTEL_CHAIN, ifnull(f2.result, f1.HOTEL_LOCATION) as HOTEL_LOCATION, ifnull(f3.result, f1.HOTEL_OWNER) as HOTEL_LOCATION, from BUSINESSTABLE f1 left outer join lateral ( select 'NULL' result from BUSINESSTABLE f2b where f1.HOTEL_CHAIN=f2b.HOTEL_CHAIN and f1.HOTEL_LOCATION<>f2b.HOTEL_LOCATION fetch first rows only ) f2 on 1=1 left outer join lateral ( select 'NULL' result from BUSINESSTABLE f3b where f1.HOTEL_CHAIN=f3b.HOTEL_CHAIN and f1.HOTEL_OWNER<>f3b.HOTEL_OWNER fetch first rows only ) f3 on 1=1 解决方案,但您可以这样做:

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$Value的每个元素构建一个数据框,并添加rbind列:

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)