使用dplyr(R)中的分组数据引用向量vs行

使用dplyr(R)中的分组数据引用向量vs行,r,dplyr,mutate,R,Dplyr,Mutate,我在dplyr中使用分组数据进行高级操作时遇到一些问题。我不确定如何指定是否要引用观察级别值,以及何时可以具体引用整个向量 示例数据帧: df <- as.data.frame( rbind( c(11990, 2011, 1, 1, 2010), c(11990, 2015, 1, 0, NA), c(11990, 2017, 2, 1, NA), c(11990, 2018, 2, 1, 2016), c(11990, 2019, 2, 1,

我在dplyr中使用分组数据进行高级操作时遇到一些问题。我不确定如何指定是否要引用观察级别值,以及何时可以具体引用整个向量

示例数据帧:

df <- as.data.frame(
  rbind(
    c(11990, 2011, 1, 1, 2010),
    c(11990, 2015, 1, 0, NA),
    c(11990, 2017, 2, 1, NA),
    c(11990, 2018, 2, 1, 2016),
    c(11990, 2019, 2, 1, 2019),
    c(11990, 2020, 1, 0, NA),
    c(22880, 2013, 1, 1, NA),
    c(22880, 2014, 1, 0, 2011),
    c(22880, 2015, 1, 1, NA),
    c(22880, 2018, 2, 0, 2014),
    c(22880, 2020, 2, 0, 1979)))
names(df) <- c("id", "year", "house_apt", "moved", "year_moved")

# > df
#       id year house_apt moved year_moved
# 1  11990 2011         1     1       2010
# 2  11990 2015         1     0         NA
# 3  11990 2017         2     1         NA
# 4  11990 2018         2     1       2016
# 5  11990 2019         2     1       2019
# 6  11990 2020         1     0         NA
# 7  22880 2013         1     1         NA
# 8  22880 2014         1     0       2011
# 9  22880 2015         1     1         NA
# 10 22880 2018         2     0       2014
# 11 22880 2020         2     0       1979
很明显,这里的“年”指的是每一行的值。即使我(出于某种原因)通过分组来完成,情况也是如此。然而,如果我要做以下两个涉及向量运算的运算:

df %>% mutate(sum(year))
df %>% group_by(id) %>% mutate(sum(year))
dplyr将“年”理解为整个组的年值的整个向量

然而,现在我在一个操作中遇到了很多麻烦,在这个操作中,我想使用行值还是整个向量来进行
mutate
是不明确的。在我的数据框中,我想为搬家但直到后来的调查实例才记录搬家日期的个人创建一个变量,即猜测的搬家年份。请注意,数据非常混乱,一些我们想忽略的毫无意义的移动日期

因此,我想为每一行创建一个“猜测”值,其中记录了一个人移动但没有移动的年份。我希望操作查看每个个体的移动日期的整个向量,子集仅包括早于当前年份的日期,并为当前行选择最接近年份的日期。详细示例:如果我们查看第3行,该个人在该年搬家,但没有搬家日期。因此,我们希望查看此人的全年移动向量
(2010,NA,NA,2016,2019,NA)
,并选择最接近且最好早于第3行年度值(
2017
)的一个。因此,猜测值为
2016

通过给定的年份和值向量获得我们想要的值很简单:

year <- 2017
year_moved <- c(2010, 2016, 2017)
year_moved[which.min(year-(year_moved[year_moved<year & !is.na(year_moved)]))]
# [1] 2016
rm(year, year_moved)

year我认为修改当前尝试以获得正确结果的最直接方法是将猜测操作包装在
sapply
中,以便每年分别计算一次猜测:

df %>% 
    group_by(id) %>%
    mutate(
        year_guess = ifelse(
            moved==1 & is.na(year_moved),
            sapply(year, function(x) year_moved[which.min(x-(year_moved[year_moved < x]))]),
            NA)
        )
df%>%
分组依据(id)%>%
变异(
年份猜=ifelse(
移动==1&is.na(移动年份),
sapply(年份,函数(x)年移动[其中.min(x-(年移动[年移动
我还不能完全解开这个过程的逻辑,但我认为,正如我所写的那样,你的猜测过程有点复杂,很容易矢量化(尽管如果你用稍微不同的方式处理它,它可能是)

输出:

# A tibble: 11 x 6
# Groups:   id [2]
      id  year house_apt moved year_moved year_guess
   <dbl> <dbl>     <dbl> <dbl>      <dbl>      <dbl>
 1 11990  2011         1     1       2010         NA
 2 11990  2015         1     0         NA         NA
 3 11990  2017         2     1         NA       2016
 4 11990  2018         2     1       2016         NA
 5 11990  2019         2     1       2019         NA
 6 11990  2020         1     0         NA         NA
 7 22880  2013         1     1         NA       2011
 8 22880  2014         1     0       2011         NA
 9 22880  2015         1     1         NA       2014
10 22880  2018         2     0       2014         NA
11 22880  2020         2     0       1979         NA
#一个tible:11 x 6
#组别:id[2]
身份证年份房屋\u公寓搬家年份\u搬家年份\u猜测
119902011 1112010NA
2 11990 2015 1 0不适用
2017年3月11990日2016年2月1日不适用
4 11990 2018 2 1 2016不适用
5 11990 2019 2 1 2019北美
61199020010NA
7 22880 2013 1 2011年不适用
8 22880 2014 1 0 2011不适用
9 22880 2015 1 1 2014年不适用
1022880 2018年2 0 2014年不适用
11222880 2020 200 1979北美

Re“很明显,这里的“年”指的是每一行的值。”。。。没那么明显<代码>年份+2
是一个矢量化操作(循环使用
2
dplyr
始终将变量“理解”为整个向量(可能在组中),而不是观察级别的单个值。哦,有趣。所以我问题的全部前提是错误的。基本上,在mutate中从不引用行值,而是调用整个向量。现在你指出了这是非常直观的。那么,使用@Marius在下面指出的apply函数是执行只涉及该行的值而不是整个向量的操作的唯一方法吗?或者有其他更普遍的方法来做到这一点。我正试图理解更多矢量化/非矢量化函数背后的直觉,因此任何帮助都将是巨大的。这不是唯一的方法。还有
rowwise()
before
mutate()
策略(按行分组,因此
mutate
中的变量指长度为1的向量。比较@bouncyball的注释和此答案中的一些其他可能性,例如:(
map
和变体类似于
s/l/vapply
)谢谢@Marius的介绍。这对解决手头的具体问题有很大帮助。re:“我还没有完全解开这个问题的逻辑,但我认为,正如我所写的,你的猜测过程有点复杂,很容易矢量化(尽管如果你用稍微不同的方式来处理它,可能会很复杂)。”有人对此有什么想法吗?对一般解决方案感兴趣。另外,(供其他人参考)sapply函数最好封装在unlist()调用中,以将格式良好的向量传递到df,而不是列表。
df %>% 
    group_by(id) %>%
    mutate(
        year_guess = ifelse(
            moved==1 & is.na(year_moved),
            sapply(year, function(x) year_moved[which.min(x-(year_moved[year_moved < x]))]),
            NA)
        )
# A tibble: 11 x 6
# Groups:   id [2]
      id  year house_apt moved year_moved year_guess
   <dbl> <dbl>     <dbl> <dbl>      <dbl>      <dbl>
 1 11990  2011         1     1       2010         NA
 2 11990  2015         1     0         NA         NA
 3 11990  2017         2     1         NA       2016
 4 11990  2018         2     1       2016         NA
 5 11990  2019         2     1       2019         NA
 6 11990  2020         1     0         NA         NA
 7 22880  2013         1     1         NA       2011
 8 22880  2014         1     0       2011         NA
 9 22880  2015         1     1         NA       2014
10 22880  2018         2     0       2014         NA
11 22880  2020         2     0       1979         NA