преобразовать одноименные элементы списка с неравной длиной в кадр данных - PullRequest
2 голосов
/ 25 октября 2019

Я знаю, что существует так много вопросов о списках данных, но я не могу найти решение этой простой проблемы. Допустим, у меня есть:

library(tidyverse)
library(janitor)
df <- data.frame( group = c(rep("A",3), rep("B", 6)),
                  test_value = c(0,1,2, 0,1,2,3,4,5))
df_list <- df %>% 
  split(.$group) %>% 
  map(~tabyl(.x$test_value))
df_list  
# $A
#  .x$test_value n   percent
#              0 1 0.3333333
#              1 1 0.3333333
#              2 1 0.3333333

# $B
#  .x$test_value n   percent
#              0 1 0.1666667
#              1 1 0.1666667
#              2 1 0.1666667
#              3 1 0.1666667
#              4 1 0.1666667
#              5 1 0.1666667

Все, что я хочу сделать, - это преобразовать его в этот именованный кадр данных следующего содержания:

  A_test_value   A_n A_percent B_test_value   B_n B_percent
         <dbl> <dbl>     <dbl>        <dbl> <dbl>     <dbl>
1            0     1     0.333            0     1     0.167
2            1     1     0.333            1     1     0.167
3            2     1     0.333            2     1     0.167
4           NA    NA    NA                3     1     0.167
5           NA    NA    NA                4     1     0.167
6           NA    NA    NA                5     1     0.167

Я видел это, но оно немного отличается ( Преобразование вложенного списка (неравной длины) во фрейм данных )

У кого-нибудь есть быстрое решение (возможно, типа dplyr), пожалуйста?

Ответы [ 3 ]

5 голосов
/ 25 октября 2019

Возможно, вы хотите присоединиться?

library(dplyr)
library(purrr)
library(janitor)

df %>% 
  group_split(group) %>% 
  map(~tabyl(.x, test_value)) %>%
  reduce(full_join, by = "test_value")

  test_value n.x percent.x n.y percent.y
1          0   1 0.3333333   1 0.1666667
2          1   1 0.3333333   1 0.1666667
3          2   1 0.3333333   1 0.1666667
4          3  NA        NA   1 0.1666667
5          4  NA        NA   1 0.1666667
6          5  NA        NA   1 0.1666667

Для именованной выходной группы, указывающей группу, вы можете сделать:

df %>% 
  split(.$group) %>%
  map(~tabyl(.x, test_value)) %>%
  imap(~set_names(.x, ifelse(names(.x) != "test_value", paste(.y, names(.x), sep = "_"), names(.x)))) %>%
  reduce(full_join, by = "test_value")

  test_value A_n A_percent B_n B_percent
1          0   1 0.3333333   1 0.1666667
2          1   1 0.3333333   1 0.1666667
3          2   1 0.3333333   1 0.1666667
4          3  NA        NA   1 0.1666667
5          4  NA        NA   1 0.1666667
6          5  NA        NA   1 0.1666667
2 голосов
/ 25 октября 2019

Во-первых, вы можете сначала добавить суффиксы столбцов в соответствии с подсписками names в главном списке, а затем добавить копию дубликатов столбцов значений с одинаковыми именами, например, от "by" до merge (так называемое соединение).

df_list <- Map(function(x) {
  out <- `names<-`(
    df_list[[x]], paste0(x, "_", c("test_value", "n", "percent")))
  out <- cbind(out, by=out[,1])
  }, names(df_list))

res <- merge(df_list$A, df_list$B, all=TRUE)[, -1]
res
#   A_test_value A_n A_percent B_test_value B_n B_percent
# 1            0   1 0.3333333            0   1 0.1666667
# 2            1   1 0.3333333            1   1 0.1666667
# 3            2   1 0.3333333            2   1 0.1666667
# 4           NA  NA        NA            3   1 0.1666667
# 5           NA  NA        NA            4   1 0.1666667
# 6           NA  NA        NA            5   1 0.1666667
1 голос
/ 26 октября 2019

Базовый раствор R:

# Create the data: 

df <- data.frame(group = c(rep("A",3), rep("B", 6)),

                  test_value = c(0,1,2, 0,1,2,3,4,5))

# Create the dataframe list, splitting on group: 

df_list <- lapply(split(df, df$group), data.frame)

# Create the extra vars: 

df_list <- mapply(cbind,  df_list,  "n" = 1,  "percent" = 1/sapply(df_list, nrow), SIMPLIFY = FALSE)

# Row bind the dataframe list together into a single dataframe: 

df2 <- data.frame(do.call(rbind, df_list), row.names = NULL, stringsAsFactors = FALSE)

# Spread by the test_value:

df2 <- reshape(df2, idvar = 'test_value', ids = unique(df2$test_value), direction = 'wide', timevar = 'group')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...