创建一个等于另一个(分组)观察值的变量

问题描述 投票:0回答:1

首先,感谢所有为本网站做出贡献的人。它对我弄清楚 R 很有帮助。

我有一个结构如下的数据集(非常过于简单的示例):

#> Var 1   Var2 Var 3    Var 4    Var5
#>  1         1 1         A        1200
#>  2         1 2         A        2300
#>  3         1 1         A        1200
#>  4         2 2         A        2300
#>  5         2 1         B        1200
#>  6         3 2         B        2300
#>  7         3 1         B        1200
#>  8         3 2         B        2300
#>  9         3 1         B        1200
#> 10         4 2         B        2300

我想 (1) 根据 Var 1、Var 2 和 Var 3 将数据分组在一起;这往往会创建两行组。在这些配对中,我希望 (2) 根据配对中其他观测值的 Var 4 和 Var 5 的值创建一个新变量 (Var 6)。在步骤 (2) 中,我基本上想创建一个变量来交换每对 Var 5 的观察结果。

代码如下所示:

df2 <- df1 %>% 
  dplyr::group_by(Var1, Var2, Var3) %>% 
  dplyr::mutate(Var6 = case_when(Var5 == A ~ Var5[Var5 == B]), Var5 == B ~ Var5[Var5 == A])
)
Output should look like this: 

#> Var 1   Var2 Var 3    Var 4    Var5    Var 6
#>  1         1 1         A        1200    2300
#>  2         1 2         A        2300    1200
#>  3         1 1         A        1200    2300
#>  4         2 2         A        2300    1200
#>  5         2 1         B        1200    2300
#>  6         3 2         B        2300    1200
#>  7         3 1         B        1200    2300
#>  8         3 2         B        2300    1200
#>  9         3 1         B        1200    2300
#> 10         4 2         B        2300    1200



使用上面的代码,我收到以下错误消息:

`Var 6` must be size 1, not 0.
Backtrace:
 1. ... %>% ...
 9. dplyr:::dplyr_internal_error(...)

r dplyr case
1个回答
0
投票

我要更改

Var1
,然后仅对其进行分组,这样我们就可以获得 2 行的组。我还将确保我们有几个仅包含 1 行的组,用于演示值交换逻辑。您不需要第一个
mutate
与您的真实数据,我们假设它有足够的可变性来为您提供您所说的期望的 2 行。

df1 %>%
  mutate(Var1 = replace(rep(1:5, each=2), 10, 6)) %>%
  group_by(Var1) %>%
  mutate(Var6 = if (n() == 1) Var5 else rev(Var5)) %>%
  ungroup()
# # A tibble: 10 × 6
#     Var1  Var2  Var3 Var4   Var5  Var6
#    <dbl> <int> <int> <chr> <int> <int>
#  1     1     1     1 A      1200  2300
#  2     1     1     2 A      2300  1200
#  3     2     1     1 A      1200  2300
#  4     2     2     2 A      2300  1200
#  5     3     2     1 B      1200  2300
#  6     3     3     2 B      2300  1200
#  7     4     3     1 B      1200  2300
#  8     4     3     2 B      2300  1200
#  9     5     3     1 B      1200  1200
# 10     6     4     2 B      2300  2300

这确实依赖于它们仅由 1 或 2 行组成,绝不会更多。如果这是一个因素,那么

rev(.)
黑客攻击很可能会失败。如果是这样的话,那么我们需要在有多行时想出逻辑。

为此,我们可以生成一个简单的函数,一旦“这一行”的值被删除,该函数就会获取第一个值。事实上,我会给你两个选择:

  • Var6a:负索引(
    Var5[-i][1]
    )确保删除该行的值,并获取第一个剩余值;如果由于某种原因你在一个组中重复
    Var5
    ,那么这可能会导致相同的值
  • Var6c
    setdiff
    ,从候选中删除该行的值并返回第一个剩余值;如果你在一个组中有重复
    Var5
    ,这个方法保证你不会得到相同的值

对于这两者中的每一个,我还使用

coalesce
提供清理操作,以防您 must
Var6
中具有值,默认为原始
Var5
。当组只有 1 行或
Var5
不变时,这非常有用。

df1 %>%
  mutate(Var1 = replace(rep(1:5, each=2), 10, 6)) %>%
  group_by(Var1) %>%
  mutate(
    Var6a = sapply(row_number(), function(i) Var5[-i][1]), 
    Var6b = coalesce(Var6a, Var5), 
    Var6c = sapply(Var5, function(v5) setdiff(Var5, v5)[1]), 
    Var6d = coalesce(Var6c, Var5)
  ) %>%
  ungroup()
# # A tibble: 10 × 9
#     Var1  Var2  Var3 Var4   Var5 Var6a Var6b Var6c Var6d
#    <dbl> <int> <int> <chr> <int> <int> <int> <int> <int>
#  1     1     1     1 A      1200  2300  2300  2300  2300
#  2     1     1     2 A      2300  1200  1200  1200  1200
#  3     2     1     1 A      1200  2300  2300  2300  2300
#  4     2     2     2 A      2300  1200  1200  1200  1200
#  5     3     2     1 B      1200  2300  2300  2300  2300
#  6     3     3     2 B      2300  1200  1200  1200  1200
#  7     4     3     1 B      1200  2300  2300  2300  2300
#  8     4     3     2 B      2300  1200  1200  1200  1200
#  9     5     3     1 B      1200    NA  1200    NA  1200
# 10     6     4     2 B      2300    NA  2300    NA  2300
© www.soinside.com 2019 - 2024. All rights reserved.