R& dplyr:为选定的组成员分配组级别特征

时间:2018-03-21 05:23:34

标签: r dplyr iteration summary

我有一个大型数据集,通过分组变量= grp划分为许多小组;组中的所有成员按较大数据集的顺序连续。每个组的成员都有一个id代码(= id),并从1开始按顺序编号。在一个组中,某些成员符合逻辑标准= is_child。每个成员都有一个变量(momloc),其中包含另一个组成员(母亲,如果有的话)的零或ID号。

我希望为数据集中的每个人分配momloc等于其ID的组成员数,如果没有,则为零。我试图在dplyr中执行此操作,因为我已经在那里设置了组,并且我有可用的代码,但它是嵌套ifelse函数的Rube Goldberg装置,为中间值添加了两个附加列,其中一个包含向量,经历了三次数据集,并且非常慢。必须有一个比这更好的方法。我在变异,处理行和汇总,处理组的不同语法中纠缠不清。

以下是简化的数据集和期望的结果

grp      <- c(1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2)
id       <- c(1, 2, 3, 4, 1, 2, 3, 4, 5, 6, 7)
is_child <- c(0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0)
momloc   <- c(0, 0, 2, 2, 0, 0, 0, 3, 2, 2, 2)
data <- tibble(grp, id, is_child, momloc)

期望的输出:

out = c(0, 2, 0, 0, 0, 2, 1, 0, 0, 0, 0)

3 个答案:

答案 0 :(得分:1)

我很容易误解你的问题。但我认为table() momlocgrp正是您所寻找的:

library(tidyverse)
grp      <- c(1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2) %>% factor
id       <- c(1, 2, 3, 4, 1, 2, 3, 4, 5, 6, 7) %>% factor
is_child <- c(0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0)
momloc   <- c(0, 0, 2, 2, 0, 0, 0, 3, 2, 2, 2)
data <- tibble(grp, id, is_child, momloc)

out = c(0, 2, 0, 0, 0, 2, 1, 0, 0, 0, 0)

data2 <- filter(data, is_child == 1)

data3 <- table(id = factor(data2$momloc, levels = levels(id)), grp = data2$grp) %>% 
    as.data.frame(responseName = "out")

left_join(data, data3, by = c("grp", "id"))
#> # A tibble: 11 x 5
#>    grp   id    is_child momloc   out
#>    <fct> <fct>    <dbl>  <dbl> <int>
#>  1 1     1           0.     0.     0
#>  2 1     2           0.     0.     2
#>  3 1     3           1.     2.     0
#>  4 1     4           1.     2.     0
#>  5 2     1           0.     0.     0
#>  6 2     2           0.     0.     2
#>  7 2     3           0.     0.     1
#>  8 2     4           1.     3.     0
#>  9 2     5           1.     2.     0
#> 10 2     6           1.     2.     0
#> 11 2     7           0.     2.     0

all(cbind(data, out) == left_join(data, data3, by = c("grp", "id")))
#> [1] TRUE

请注意,我更改了grpid以考虑第2行和第3行。

答案 1 :(得分:1)

以下是使用dplyr的解决方案。

data.moms <- data %>% 
  split(grp) %>%
  lapply(., function(data.grp) {
    data.grp %>% group_by(id, grp) %>% summarise(NumChildren = sum(.$momloc == id))
  }) %>% do.call(rbind, .)

我们首先使用split(grp)将数据框拆分为多个数据框,每个数据框一个。{/ p>

然后,我们使用lapply()将操作应用于列表中的每个data.frame。 对于每个数据框架,我们按idgrp分组 - 即使这意味着唯一的“群组”。我们也可以仅在id上进行分组,但在两者上进行分组意味着我们可以保留两列。

现在,列表中的每个data.frame都包含3列

  • ID
  • GRP
  • NUMCHILDREN

现在,我们可以使用do.call(rbind, .)重新组合汇总的数据框。

> data.moms
# A tibble: 11 x 3
# Groups:   id [7]
      id   grp NumChildren
   <dbl> <dbl>       <int>
 1  1.00  1.00           0
 2  2.00  1.00           2
 3  3.00  1.00           0
 4  4.00  1.00           0
 5  1.00  2.00           0
 6  2.00  2.00           3
 7  3.00  2.00           1
 8  4.00  2.00           0
 9  5.00  2.00           0
10  6.00  2.00           0
11  7.00  2.00           0

答案 2 :(得分:0)

我仅使用dplyr提出解决方案。

首先,我只保留孩子(假设您只想将它​​们计为out[6] = 2而不是3)。然后,我使用momloc创建count()的频率表,并将其合并到原始数据中。

data %>%
    filter(is_child == 1) %>% # only count for children
    group_by(grp) %>%
    count(momloc) %>%
    right_join(data, by = c("grp" = "grp", "momloc" = "id")) %>%
    rename(
        id = momloc,
        momloc = momloc.y,
        out = n
    ) %>%
    mutate(out = ifelse(is.na(out), 0, out))

#> # A tibble: 11 x 5
#> # Groups:   grp [2]
#>      grp    id   out is_child momloc
#>    <dbl> <dbl> <dbl>    <dbl>  <dbl>
#>  1     1     1     0        0      0
#>  2     1     2     2        0      0
#>  3     1     3     0        1      2
#>  4     1     4     0        1      2
#>  5     2     1     0        0      0
#>  6     2     2     2        0      0
#>  7     2     3     1        0      0
#>  8     2     4     0        1      3
#>  9     2     5     0        1      2
#> 10     2     6     0        1      2
#> 11     2     7     0        0      2