如何根据 R 中其他列的多个条件创建多个新列?

How to create multiple new columns based on multiple conditions of other columns in R?

我想弄清楚如何根据其他列创建新列并将另一列的值作为观察值插入新创建的列中。 不确定如何用语言清楚地解释这一点,所以我将展示一个例子。

基本上我的数据是这样的:

code spec grid month day depth number
01 31 1 6 17 5 1
01 33 1 6 17 5 2
01 45 1 6 17 10 15
02 45 12 6 17 10 34
02 45 12 7 19 15 1
03 31 15 8 27 15 30
03 33 16 9 13 20 34
03 31 18 10 17 25 100

我的数据集有 2,514 行。

'spec'栏是物种代码。我想创建新的列,其中包含实际的物种名称(对于每个物种代码)及其各自的编号作为观察值(行)。

例如(simplified/mock 出于隐私目的的数据)。 让我们说物种代码:31 ==蚊子,33 ==狮子,45 ==鱼......等等。 我希望我的数据像这样结束:

code mosquito lion fish grid month day depth
01 1 0 0 1 6 17 5
01 0 2 0 1 6 17 5
01 0 0 15 1 6 17 10
02 0 0 34 12 6 17 10
02 0 0 1 12 7 19 15
03 30 0 0 15 8 27 15
03 0 34 0 16 9 13 20
03 100 0 0 18 10 17 25
  1. 包含每个独特物种代码的物种名称的新列(我的数据中可能有大约 15 个物种,因此应该有 ~15 个新列)
  2. 每个物种都应该有其各自的 'number',如果物种没有被计算在内,它应该有一个 '0'
  3. 设置完成后,'number' 和 'spec' 列可以删除。 *当然,数据需要与其各自的日期、月份、代码、网格等对齐,因此没有其他内容是 changed/modified 来自原始数据

我在网上看了几个小时,但一直没能找到明确的答案... 我找到了更简单的解决方案,但无法满足我的问题。

我试过 case_when、if_else 和 sapply,但似乎无法正常工作。 我希望这个问题很清楚。很高兴进一步澄清。 有什么建议么? 谢谢!

你可以使用

library(dplyr)
library(tidyr)

df1 %>% 
  left_join(df2, by = "spec") %>% 
  pivot_wider(values_from = "number", values_fill = 0) %>% 
  select(code, mosquito, lion, fish, grid, month, day, depth)

这个returns

# A tibble: 8 x 8
  code  mosquito  lion  fish  grid month   day depth
  <chr>    <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 01           1     0     0     1     6    17     5
2 01           0     2     0     1     6    17     5
3 01           0     0    15     1     6    17    10
4 02           0     0    34    12     6    17    10
5 02           0     0     1    12     7    19    15
6 03          30     0     0    15     8    27    15
7 03           0    34     0    16     9    13    20
8 03         100     0     0    18    10    17    25

我使用了两个数据框:你显示的数据

structure(list(code = c("01", "01", "01", "02", "02", "03", "03", 
"03"), spec = c(31, 33, 45, 45, 45, 31, 33, 31), grid = c(1, 
1, 1, 12, 12, 15, 16, 18), month = c(6, 6, 6, 6, 7, 8, 9, 10), 
    day = c(17, 17, 17, 17, 19, 27, 13, 17), depth = c(5, 5, 
    10, 10, 15, 15, 20, 25), number = c(1, 2, 15, 34, 1, 30, 
    34, 100)), class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame"
), row.names = c(NA, -8L), spec = structure(list(cols = list(
    code = structure(list(), class = c("collector_character", 
    "collector")), spec = structure(list(), class = c("collector_double", 
    "collector")), grid = structure(list(), class = c("collector_double", 
    "collector")), month = structure(list(), class = c("collector_double", 
    "collector")), day = structure(list(), class = c("collector_double", 
    "collector")), depth = structure(list(), class = c("collector_double", 
    "collector")), number = structure(list(), class = c("collector_double", 
    "collector"))), default = structure(list(), class = c("collector_guess", 
"collector")), skip = 1L), class = "col_spec"))

和一个data.frame用于将spec转换为真正的物种名称:

structure(list(spec = c(31, 33, 45), name = c("mosquito", "lion", 
"fish")), class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame"
), row.names = c(NA, -3L), spec = structure(list(cols = list(
    spec = structure(list(), class = c("collector_double", "collector"
    )), name = structure(list(), class = c("collector_character", 
    "collector"))), default = structure(list(), class = c("collector_guess", 
"collector")), skip = 1L), class = "col_spec"))

你可以这样做:

library(tidyverse)

df %>% 
  mutate(spec = case_when(
      spec == 31 ~ 'mosquito', 
      spec == 33 ~ 'lion', 
      spec == 45 ~ 'fish',
      TRUE ~ NA_character_),
      id = row_number()) %>%
  pivot_wider(names_from = spec, values_from = number) %>%
  mutate(across(everything(), ~ replace_na(.x, 0)))
#> # A tibble: 8 x 9
#>    code  grid month   day depth    id mosquito  lion  fish
#>   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>    <dbl> <dbl> <dbl>
#> 1     1     1     6    17     5     1        1     0     0
#> 2     1     1     6    17     5     2        0     2     0
#> 3     1     1     6    17    10     3        0     0    15
#> 4     2    12     6    17    10     4        0     0    34
#> 5     2    12     7    19    15     5        0     0     1
#> 6     3    15     8    27    15     6       30     0     0
#> 7     3    16     9    13    20     7        0    34     0
#> 8     3    18    10    17    25     8      100     0     0

请注意,您需要将您的其他物种映射到 case_when

中的 spec 编号

reprex package (v2.0.1)

于 2022-04-10 创建

来自问题的可重现格式的数据:

``` r
df <- structure(list(code = c(1L, 1L, 1L, 2L, 2L, 3L, 3L, 3L), spec = c(31L, 
33L, 45L, 45L, 45L, 31L, 33L, 31L), grid = c(1L, 1L, 1L, 12L, 
12L, 15L, 16L, 18L), month = c(6L, 6L, 6L, 6L, 7L, 8L, 9L, 10L
), day = c(17L, 17L, 17L, 17L, 19L, 27L, 13L, 17L), depth = c(5L, 
5L, 10L, 10L, 15L, 15L, 20L, 25L), number = c(1L, 2L, 15L, 34L, 
1L, 30L, 34L, 100L)), class = "data.frame", row.names = c(NA, 
-8L))

df
#>   code spec grid month day depth number
#> 1    1   31    1     6  17     5      1
#> 2    1   33    1     6  17     5      2
#> 3    1   45    1     6  17    10     15
#> 4    2   45   12     6  17    10     34
#> 5    2   45   12     7  19    15      1
#> 6    3   31   15     8  27    15     30
#> 7    3   33   16     9  13    20     34
#> 8    3   31   18    10  17    25    100