如何将列表值的列拆分为多个列?

3
我有以下情况,列power_dbm0的值是一个列表。所有元素都是长度为11的列表。
# A tibble: 10 x 2
   real_pat power_dbm0
   <chr>    <list>    
 1 am       <dbl [11]>
 2 fax      <dbl [11]>
 3 fp       <dbl [11]>
 4 fpw      <dbl [11]>

我想知道如何将这些值拆分,使每个订单成为一个新的列。最好像dplyr一样提供解决方案。我尝试过使用tidyr中的unnest或separate函数来解决问题,但没有成功。
谢谢!
以下是数据:
structure(list(real_pat = c("am", "fax", "fp", "fpw"), power_dbm0 = list(
    structure(c(0.0142857142857143, 0.0742857142857143, 0.111428571428571, 
    0.138571428571429, 0.208571428571429, 0.278571428571429, 
    0.368571428571429, 0.508571428571429, 0.648571428571429, 
    0.771428571428571, 0.871428571428571), .Names = c("0%", "10%", 
    "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%"
    )), structure(c(0.342857142857143, 0.342857142857143, 0.342857142857143, 
    0.342857142857143, 0.342857142857143, 0.342857142857143, 
    0.342857142857143, 0.342857142857143, 0.342857142857143, 
    0.342857142857143, 0.342857142857143), .Names = c("0%", "10%", 
    "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%"
    )), structure(c(0.0142857142857143, 0.622857142857143, 0.808571428571429, 
    0.851428571428571, 0.857142857142857, 0.871428571428571, 
    0.874285714285714, 0.885714285714286, 0.894285714285714, 
    0.911428571428571, 0.914285714285714), .Names = c("0%", "10%", 
    "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%"
    )), structure(c(0.514285714285714, 0.514285714285714, 0.514285714285714, 
    0.514285714285714, 0.514285714285714, 0.514285714285714, 
    0.514285714285714, 0.514285714285714, 0.514285714285714, 
    0.514285714285714, 0.514285714285714), .Names = c("0%", "10%", 
    "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%"
    )))), .Names = c("real_pat", "power_dbm0"), row.names = c(NA, 
-4L), class = c("tbl_df", "tbl", "data.frame"))

1
请使用 dput 显示示例以及您期望的输出。不清楚每个列表元素中包含什么。 - akrun
谢谢提示,我已经添加了。 - Rafael Toledo
你需要 df1 %>% mutate(power_dbm0 = map(power_dbm0, as_tibble)) %>% unnest 吗? - akrun
不,我想把每个订单作为一列,而不是将所有值融合在同一列中。 - Rafael Toledo
请检查我发布的解决方案。 - akrun
3个回答

8

1) 这是一个单行的基础解决方案:

with(dd, do.call("rbind", setNames(power_dbm0, real_pat)))

提供:

            0%        10%       20%       30%       40%       50%       60%
am  0.01428571 0.07428571 0.1114286 0.1385714 0.2085714 0.2785714 0.3685714
fax 0.34285714 0.34285714 0.3428571 0.3428571 0.3428571 0.3428571 0.3428571
fp  0.01428571 0.62285714 0.8085714 0.8514286 0.8571429 0.8714286 0.8742857
fpw 0.51428571 0.51428571 0.5142857 0.5142857 0.5142857 0.5142857 0.5142857
          70%       80%       90%      100%
am  0.5085714 0.6485714 0.7714286 0.8714286
fax 0.3428571 0.3428571 0.3428571 0.3428571
fp  0.8857143 0.8942857 0.9114286 0.9142857
fpw 0.5142857 0.5142857 0.5142857 0.5142857

2) 或者将 real_pat 作为列而不是名称:

with(dd, data.frame(real_pat, do.call("rbind", power_dbm0), check.names = FALSE))

提供:

  real_pat         0%        10%       20%       30%       40%       50%
1       am 0.01428571 0.07428571 0.1114286 0.1385714 0.2085714 0.2785714
2      fax 0.34285714 0.34285714 0.3428571 0.3428571 0.3428571 0.3428571
3       fp 0.01428571 0.62285714 0.8085714 0.8514286 0.8571429 0.8714286
4      fpw 0.51428571 0.51428571 0.5142857 0.5142857 0.5142857 0.5142857
        60%       70%       80%       90%      100%
1 0.3685714 0.5085714 0.6485714 0.7714286 0.8714286
2 0.3428571 0.3428571 0.3428571 0.3428571 0.3428571
3 0.8742857 0.8857143 0.8942857 0.9114286 0.9142857
4 0.5142857 0.5142857 0.5142857 0.5142857 0.5142857

3) 使用dplyr,我们可以这样写:

library(dplyr)
dd %>% { bind_cols(select(., real_pat), bind_rows(!!!.$power_dbm0)) }

提供:

# A tibble: 4 x 12
  real_pat   `0%`  `10%` `20%` `30%` `40%` `50%` `60%` `70%` `80%` `90%` `100%`
  <chr>     <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>
1 am       0.0143 0.0743 0.111 0.139 0.209 0.279 0.369 0.509 0.649 0.771  0.871
2 fax      0.343  0.343  0.343 0.343 0.343 0.343 0.343 0.343 0.343 0.343  0.343
3 fp       0.0143 0.623  0.809 0.851 0.857 0.871 0.874 0.886 0.894 0.911  0.914
4 fpw      0.514  0.514  0.514 0.514 0.514 0.514 0.514 0.514 0.514 0.514  0.514

3a) 或者使用 bind_rows 函数的 .id= 参数和 magrittr 包中的 %$% 符号:

library(dplyr)
library(magrittr)

dd %$%
   setNames(power_dbm0, real_pat) %$%
   bind_rows(!!!., .id = "real_pat")

提供:

# A tibble: 4 x 12
  real_pat   `0%`  `10%` `20%` `30%` `40%` `50%` `60%` `70%` `80%` `90%` `100%`
  <chr>     <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>
1 am       0.0143 0.0743 0.111 0.139 0.209 0.279 0.369 0.509 0.649 0.771  0.871
2 fax      0.343  0.343  0.343 0.343 0.343 0.343 0.343 0.343 0.343 0.343  0.343
3 fp       0.0143 0.623  0.809 0.851 0.857 0.871 0.874 0.886 0.894 0.911  0.914
4 fpw      0.514  0.514  0.514 0.514 0.514 0.514 0.514 0.514 0.514 0.514  0.514

3b) 或者没有%$%

library(dplyr)

dd %>%
   { setNames(.$power_dbm0, .$real_pat) } %>%
   { bind_rows(!!!., .id = "real_pat") }

提供:

# A tibble: 4 x 12
  real_pat   `0%`  `10%` `20%` `30%` `40%` `50%` `60%` `70%` `80%` `90%` `100%`
  <chr>     <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>
1 am       0.0143 0.0743 0.111 0.139 0.209 0.279 0.369 0.509 0.649 0.771  0.871
2 fax      0.343  0.343  0.343 0.343 0.343 0.343 0.343 0.343 0.343 0.343  0.343
3 fp       0.0143 0.623  0.809 0.851 0.857 0.871 0.874 0.886 0.894 0.911  0.914
4 fpw      0.514  0.514  0.514 0.514 0.514 0.514 0.514 0.514 0.514 0.514  0.514

3

1) 我们可以将“power_dbm0”列进行转置, unlist 嵌套的列表,然后与第一列拼接

library(tidyverse)
df1 %>%
   pull(power_dbm0) %>%
   transpose %>%
   map_df(unlist) %>% 
   bind_cols(df1[1], .)
# A tibble: 4 x 12
#   real_pat   `0%`  `10%` `20%` `30%` `40%` `50%` `60%` `70%` `80%` `90%` `100%`
#  <chr>     <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>
#1 am       0.0143 0.0743 0.111 0.139 0.209 0.279 0.369 0.509 0.649 0.771  0.871
#2 fax      0.343  0.343  0.343 0.343 0.343 0.343 0.343 0.343 0.343 0.343  0.343
#3 fp       0.0143 0.623  0.809 0.851 0.857 0.871 0.874 0.886 0.894 0.911  0.914
#4 fpw      0.514  0.514  0.514 0.514 0.514 0.514 0.514 0.514 0.514 0.514  0.514

2) 或者另一种选择是先进行melt操作,然后再执行spread操作。这里我们还包括了unnest,正如原帖中提到的。

library(tidyverse)
library(reshape2)
df1 %>% 
    mutate(power_dbm0 = map(power_dbm0, ~melt(.x) %>% 
                          rownames_to_column('rn') %>%
                          mutate(rn = factor(rn, levels = rn)))) %>% 
    unnest %>% 
    spread(rn, value)
# A tibble: 4 x 12
#  real_pat   `0%`  `10%` `20%` `30%` `40%` `50%` `60%` `70%` `80%` `90%` `100%`
#  <chr>     <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>
#1 am       0.0143 0.0743 0.111 0.139 0.209 0.279 0.369 0.509 0.649 0.771  0.871
#2 fax      0.343  0.343  0.343 0.343 0.343 0.343 0.343 0.343 0.343 0.343  0.343
#3 fp       0.0143 0.623  0.809 0.851 0.857 0.871 0.874 0.886 0.894 0.911  0.914
#4 fpw      0.514  0.514  0.514 0.514 0.514 0.514 0.514 0.514 0.514 0.514  0.514

3) 或者使用 pmapspread

df1 %>%
     pmap_df(~ tibble(real_pat = ..1, nm = names(..2), val = ..2))  %>%
     spread(nm, val)

注意:所有的解决方案都使用了dplyr和相关的tidyverse


4) 或者我们可以使用unlist函数将'power_dbm0'展开成向量,然后创建一个矩阵,因为它们的长度都相等,最后再与第一列绑定(使用base R)- 如果需要,列名可以更改。

data.frame(df1[1], matrix(unlist(df1$power_dbm0), ncol = 11, byrow = TRUE))

很好的解决方案,但我想知道是否存在直接的函数或更简单的过程来实现这种转换。 - Rafael Toledo

2
一个选项可以是以下内容:
cbind(df[1],t(sapply(df$power_dbm0,function(x)x)))

# real_pat         0%        10%       20%       30%       40%       50%       60%       70%       80%       90%      100%
# 1       am 0.01428571 0.07428571 0.1114286 0.1385714 0.2085714 0.2785714 0.3685714 0.5085714 0.6485714 0.7714286 0.8714286
# 2      fax 0.34285714 0.34285714 0.3428571 0.3428571 0.3428571 0.3428571 0.3428571 0.3428571 0.3428571 0.3428571 0.3428571
# 3       fp 0.01428571 0.62285714 0.8085714 0.8514286 0.8571429 0.8714286 0.8742857 0.8857143 0.8942857 0.9114286 0.9142857
# 4      fpw 0.51428571 0.51428571 0.5142857 0.5142857 0.5142857 0.5142857 0.5142857 0.5142857 0.5142857 0.5142857 0.5142857

根据@@G.Grothendieck的反馈,使用simplify2array的其他选项:

cbind(df[1],t(simplify2array(df$power_dbm0)))

@G.Grothendieck 同意。那将是更简单的选择。我会更新我的答案。 - MKR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接