基于dplyr函数从现有数据框创建一个列表

3

我目前有一个类似于这个的数据框:

df <- tibble("Fam_Name" = c("Architecture", "Arts", "Business", "Managers", "Medicine", "Science"), "Code" = c(1,1,2, 2,3, 3), "Share_2002" = c(0.116, 3.442, 2.445, 1.932, 0.985, 0.321), "Share_2018" = c(0.161, 0.232, 1.234, 0.456, 0.089, 0.06))

我想创建一个名为family的列表,其中包含三个其他列表:fam1,fam2,fam3 每个fam(i)列表都会包含两个数据框,分别称为fam_normalfam_long,这些数据框是基于dplyr函数构建的,例如:
fam_normal <- df %>% # I am not sure how to write this so that it is incorporated into the fam(i) list
              filter(Code == i) %>%
              rename("2002" = Share_2002,
                     "2018" = Share_2018)

fam_long <- fam_normal %>%
              gather(Year, Share, 3:4) %>%
              arrange(Fam_Name)

最终目标是为fam列表中的每个fam(i)绘制一个图表,其中x轴为年份,y轴为股份。
我的真实数据集有25个家族和更多年份。

1
不错的第一个问题!清晰易懂,做得好。 - asachet
顺便提一下,你可以使用 rename_at(starts_with("Share_"), ~ gsub("Share_", "", .)) 批量重命名所有的 Share_XXXXXX。如果你有很多年份,这可能会很有用。 - asachet
4个回答

2
你可以先使用rename重命名列,然后使用group_split根据Code拆分它们,最后使用map获取数据框的列表。"Original Answer"翻译成"最初的回答"。
library(tidyverse)

df %>%
  rename("2002" = Share_2002,
         "2018" = Share_2018) %>%
  group_split(Code) %>%
  map(~list(fam_normal = .x, fam_long = .x %>%
                                         gather(Year, Share, 3:4) %>%
                                         arrange(Fam_Name)))


#[[1]]
#[[1]]$fam_normal
# A tibble: 2 x 4
#  Fam_Name      Code `2002` `2018`
#  <chr>        <dbl>  <dbl>  <dbl>
#1 Architecture     1  0.116  0.161
#2 Arts             1  3.44   0.232

#[[1]]$fam_long
# A tibble: 4 x 4
#  Fam_Name      Code Year  Share
#  <chr>        <dbl> <chr> <dbl>
#1 Architecture     1 2002  0.116
#2 Architecture     1 2018  0.161
#3 Arts             1 2002  3.44 
#4 Arts             1 2018  0.232
#....

2

以下是基于R语言的解决方案:

dd <- cbind.data.frame(df[1:2], stack(df[-c(1, 2)]))
Map(list, split(df, df$Code), split(dd, dd$Code))

which gives,

$`1`
$`1`[[1]]
# A tibble: 2 x 4
  Fam_Name      Code Share_2002 Share_2018
  <chr>        <dbl>      <dbl>      <dbl>
1 Architecture     1      0.116      0.161
2 Arts             1      3.44       0.232

$`1`[[2]]
      Fam_Name Code values        ind
1 Architecture    1  0.116 Share_2002
2         Arts    1  3.442 Share_2002
7 Architecture    1  0.161 Share_2018
8         Arts    1  0.232 Share_2018

....

注意: 您可以按照惯例更改列名称


2

首先,您可以使用purrr软件包处理嵌套的tibble:

这样可以让您一起定义子列表:

Original Answer翻译成"最初的回答"

library(tidyverse)
df2 <- df %>%
  group_by(Code) %>%
  nest(.key = fam_normal) %>%
  mutate(fam_long = map(fam_normal, ~gather(.x, Year, Share, -Fam_Name) %>% 
                          arrange(Fam_Name) %>%
                          mutate(Year = parse_number(Year)))) %>%
  unnest(fam_long)

那么你可以使用ggplot2来得到绘图:
ggplot(df2, aes(x = Year, y = Share, color = Fam_Name)) + 
  geom_line(size = 2) + 
  facet_grid(Code~ .)

enter image description here


1
fam <- list()

fam$normal <- df %>% 
              filter(Code == i) %>%
              rename("2002" = Share_2002,
                     "2018" = Share_2018)

fam$long <- fam$normal %>%
              gather(Year, Share, 3:4) %>%
              arrange(Fam_Name)

现在你有一个命名为fam的列表,其中包含你的DFs。你的DFs是如此定制化,以至于dplyr解决方案可能不如这个简单的赋值清晰易懂。我非常喜欢整洁风格的编码,但当它妨碍清晰度和易读性时就不再适用了。
如果你想在管道中使用它,只需创建一个函数:
make_families <- function(df) {
 # insert code above
 # Return `fam`
 fam
}`

那么你就完成了:这将创建你所描述的列表的列表。
df %>%
  split(Fam_Name) %>%
  purrr::map(make_families)

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