【问题标题】:Is there a way to create new columns in R based on manipulations from multiple data frames?有没有办法根据来自多个数据帧的操作在 R 中创建新列?
【发布时间】:2020-03-30 17:23:23
【问题描述】:

有谁知道是否可以在一个数据框中使用变量(在我的情况下是“部署”数据框)在另一个数据框中创建变量?

例如,我有两个数据框:

df1:

   deploy <- data.frame(ID = c("20180101_HH1_1_1", "20180101_HH1_1_2", "20180101_HH1_1_3"), 
             Site_Depth = c(42, 93, 40), Num_Depth_Bins_Required = c(5, 100, 4), 
             Percent_Column_in_each_bin = c(20, 10, 25))

df2:

   sp.c <- data.frame(species = c("RR", "GS", "GT", "BR", "RS", "BA", "GS", "RS", "SH", "RR"), 
                      ct = c(25, 66, 1, 12, 30, 6, 1, 22, 500, 6), 
                      percent_dist_from_surf = c(11, 15, 33, 68, 71, 100, 2, 65, 5, 42))

我想在 df2 中创建新列,根据每个 ID 的 Percent_Column_in_each_bin 分配每个物种并计数到一个 bin。例如,在 20180101_HH1_1_3 中,将有 4 个 bin,每个 bin 占该列的 25%,所有在该列 0-25% 范围内的物种(在 df2 中)将在 bin 1 中,物种在该列的 25-50% 范围内。列将在深度 bin 2 中,依此类推。我想象的这个样子是:

    i.want.this <- data.frame(species = c("RR", "GS", "GT", "BR", "RS", "BA", "GS", "RS", "SH", "RR"), 
                      ct = c(25, 66, 1, 12, 30, 6, 1, 22, 500, 6), 
                      percent_dist_from_surf = c(11, 15, 33, 68, 71, 100, 2, 65, 5, 42),
                      '20180101_HH1_1_1_Bin' = c(1, 1, 2, 4, 4, 5, 1, 4, 1, 3),
                      '20180101_HH1_1_2_Bin' = c(2, 2, 4, 7, 8, 10, 1, 7, 1, 5), 
                      '20180101_HH1_1_3_Bin' = c(1, 1,  2, 3, 3, 4, 1, 3, 1, 2))

我对 R 很陌生,但我不确定如何实现这一点。我需要为超过 100 个 ID 执行此操作(所有 ID 都具有不同的深度、深度箱的数量以及每个箱中的列百分比),所以我希望我不需要全部手动完成。我曾尝试在 dplyr 中进行 mutate,但无法从两个不同的数据帧中提取它。我也尝试过 ifelse 语句,但我需要为每个 ID 单独运行 ifelse 语句。

我不知道我正在尝试做的事情是否可行,但我感谢您的反馈。先感谢您!

编辑:我的最终目标是为每个 ID 的每个 bin 中的每个物种找到最大计数(最大 ct)。我一直在寻找这个(使用@Ben 的建议生成的垃圾箱)正在使用 dplyr 来切片并找到最大 ID,如下所示:

    20180101_HH1_1_1 <- sp.c %>%
                        group_by(20180101_HH1_1_1, species) %>%
                        arrange(desc(ct)) %>% 
                        slice(1) %>%
                        group_by(20180101_HH1_1_1) %>%
                        mutate(Count_Total_Per_Bin = sum(ct)) %>%
                        group_by(species, add=TRUE) %>% 
                        mutate(species_percent_of_total_in_bin = 
                             paste0((100*ct/Count_Total_Per_Bin) %>%
                        mutate(ID= "20180101_HH1_1_1 ") %>%
                        ungroup()

但我必须为超过 100 个 ID 执行此操作。我想要的输出是这样的:

    end.goal <- data.frame(ID = c(rep("20180101_HH1_1_1", 8)),
                   species = c("RR", "GS", "SH", "GT", "RR", "BR", "RS", "BA"),
                   bin = c(1, 1, 1, 2, 3, 4, 4, 5),
                   Max_count_of_each_species_in_each_bin = c(11, 66, 500, 1, 6, 12, 30, 6),
                   percent_dist_from_surf = c(11, 15, 5, 33, 42, 68, 71, 100),
                   percent_each_species_max_in_each_bin = c((11/577)*100, (66/577)*100, (500/577)*100, 100, 100, (12/42)*100, (30/42)*100, 100))

我在想,通过回答最初的问题,我可以解决这个问题,但我现在看到,要为每个 ID 获取这个问题,您仍然需要做很多事情。

【问题讨论】:

    标签: r dataframe dplyr


    【解决方案1】:

    这是另一种方法,不需要循环。

    使用sapply,您可以cut 确定deploy 数据帧中每个percent_dist_from_surf 值的bin。

    res <- sapply(deploy$Percent_Column_in_each_bin, function(x) { 
      cut(sp.c$percent_dist_from_surf, seq(0, 100, by = x), include.lowest = TRUE, labels = 1:(100/x))
    })
    colnames(res) <- deploy$ID
    cbind(sp.c, res)
    

    或者使用purrr:

    library(purrr)
    
    cbind(sp.c, imap(setNames(deploy$Percent_Column_in_each_bin, deploy$ID), 
         ~ cut(sp.c$percent_dist_from_surf, seq(0, 100, by = .x), include.lowest = TRUE, labels = 1:(100/.x))
    ))
    

    输出

       species  ct percent_dist_from_surf 20180101_HH1_1_1 20180101_HH1_1_2 20180101_HH1_1_3
    1       RR  25                     11                1                2                1
    2       GS  66                     15                1                2                1
    3       GT   1                     33                2                4                2
    4       BR  12                     68                4                7                3
    5       RS  30                     71                4                8                3
    6       BA   6                    100                5               10                4
    7       GS   1                      2                1                1                1
    8       RS  22                     65                4                7                3
    9       SH 500                      5                1                1                1
    10      RR   6                     42                3                5                2
    

    编辑

    要确定每个物种、站点和 bin 的最大 ct 值,请将上述结果放入名为 res 的数据框中,然后执行以下操作。

    首先将使用pivot_longer 输入长格式。然后您可以group_by 物种、站点和 bin,并确定此组合的最大 ct

    library(tidyverse)
    
    res %>%
      pivot_longer(cols = starts_with("2018"), names_to = "site", values_to = "bin") %>%
      group_by(species, site, bin) %>%
      summarise(max_ct = max(ct)) %>%
      arrange(site, bin)
    

    输出

    # A tibble: 26 x 4
    # Groups:   species, site [21]
       species site             bin   max_ct
       <fct>   <chr>            <fct>  <dbl>
     1 GS      20180101_HH1_1_1 1         66
     2 RR      20180101_HH1_1_1 1         25
     3 SH      20180101_HH1_1_1 1        500
     4 GT      20180101_HH1_1_1 2          1
     5 RR      20180101_HH1_1_1 3          6
     6 BR      20180101_HH1_1_1 4         12
     7 RS      20180101_HH1_1_1 4         30
     8 BA      20180101_HH1_1_1 5          6
     9 GS      20180101_HH1_1_2 1          1
    10 SH      20180101_HH1_1_2 1        500
    11 GS      20180101_HH1_1_2 2         66
    12 RR      20180101_HH1_1_2 2         25
    13 GT      20180101_HH1_1_2 4          1
    14 RR      20180101_HH1_1_2 5          6
    15 BR      20180101_HH1_1_2 7         12
    16 RS      20180101_HH1_1_2 7         22
    17 RS      20180101_HH1_1_2 8         30
    18 BA      20180101_HH1_1_2 10         6
    19 GS      20180101_HH1_1_3 1         66
    20 RR      20180101_HH1_1_3 1         25
    21 SH      20180101_HH1_1_3 1        500
    22 GT      20180101_HH1_1_3 2          1
    23 RR      20180101_HH1_1_3 2          6
    24 BR      20180101_HH1_1_3 3         12
    25 RS      20180101_HH1_1_3 3         30
    26 BA      20180101_HH1_1_3 4          6
    

    【讨论】:

    • 谢谢!这正是我一直在寻找的。那么是否有可能找到每个站点的每个箱内每个物种的最大 ct 值?这意味着,如果您查看 20180101_HH1_1_1,您将拥有 RR:25、GS:66、SH:500。我的目标是在每个 ID(或采样的站点)的每个深度箱内找到每个物种的最大值。
    • 这正是我所需要的。我收到警告:警告消息:因子 bin 包含隐式 NA,即使已填写所有必需值,请考虑使用 forcats::fct_explicit_na。您知道为什么我会收到此警告吗?
    • 问题是pivot_longer 正在从值创建一个新的列 bin,这些值当前是因子(存在 NA 或因子中的不同级别)。您可以通过强制 bin 列为字符或数字类型来消除警告:pivot_longer(cols = starts_with("2018"), names_to = "site", values_to = "bin", values_ptypes = list(bin = character()))
    【解决方案2】:

    区分两个数据框的内容很有帮助。

    • df2 似乎包含来自某些站点的测量值
    • df1 似乎包含您要用来处理/汇总 df2 中的测量值的参数

    鉴于这两个数据框的这些不同用途,您最好的方法可能是每次向df2 添加一列时循环遍历df1 的所有行。类似于以下内容:

    max_dist = max(df2$percent_dist_from_surf)
    
    for(ii in 1:nrow(df1)){
    
      # extract parameters
      this_ID = df1[[ii,"ID"]]
      this_depth = df1[[ii,"Site_Depth"]]
      this_bins = df1[[ii,"Num_Depth_Bins_Required"]]
      this_percent = df1[[ii,"Percent_Column_in_each_bin"]]
    
      # add column to df2
      df2 = df2 %>%
        mutate(!!sym(this_ID) := insert_your_calculation_here)
    }
    

    代码的!!sym(this_ID) := 部分允许动态命名输出列。

    我可以确定你想要的insert_your_calculation_here 的公式是ceil(percent_dist_from_surf / max_dist * this_bins)

    【讨论】:

      猜你喜欢
      • 2021-09-22
      • 1970-01-01
      • 1970-01-01
      • 2021-12-11
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      • 2020-01-02
      • 1970-01-01
      相关资源
      最近更新 更多