如何使用 lower.tri 中匹配的整数填充矩阵的 upper.tri?

How do I populate upper.tri of matrix with matched integers from the lower.tri?

问题

我有一个用整数编码的家庭关系数据框,其中 R01person Nperson 1 的关系,R02 他们与 [=19= 的关系]等

然而,只有每个家庭矩阵的lower.tri被编码,所以我试图写一个函数来matchupper.tri中的正确关系。

关系

关系用整数编码如下:

1 = 配偶,2 = 同居伴侣,3 = Son/daughter,4 = 继son/daughter,5 = 福斯特 child, 6 = Son-in-law/daughter-in-law, 7 = Parent/guardian, 8 = Step-parent, 9 = 福斯特 parent, 10 = Parent-in-law, 11 = Brother/sister, 12 = Step-brother/sister, 13 = 福斯特 brother/sister, 14 = Brother/sister-in-law, 15 = Grand-child, 16 = Grand-parent, 17 = 其他亲戚,18 = 其他 non-relative.

因此关系是:

rel = c("1" = 1, "2" = 2, "3" = 7, "4" = 8, "5" = 9, "6" = 10, "7" = 3, "8" = 4, "9" = 5, "10" = 6, "11" = 11, "12" = 12, "13" = 13, "14" = 14, "15" = 16, "16" = 15, "17" = 17, "18" = 18)

示例数据

   household person R01 R02 R03 R04 R05 R06
1          1      1  NA  NA  NA  NA  NA  NA
2          1      2   1  NA  NA  NA  NA  NA
3          1      3   3   3  NA  NA  NA  NA
4          1      4   3   3  11  NA  NA  NA
5          2      1  NA  NA  NA  NA  NA  NA
6          2      2   3  NA  NA  NA  NA  NA
7          2      3  15   3  NA  NA  NA  NA
8          3      1  NA  NA  NA  NA  NA  NA
9          3      2  18  NA  NA  NA  NA  NA
10         4      1  NA  NA  NA  NA  NA  NA
11         5      1  NA  NA  NA  NA  NA  NA
12         5      2   5  NA  NA  NA  NA  NA

需要输出

   household person R01 R02 R03 R04 R05 R06
1          1      1  NA   1   7   7  NA  NA
2          1      2   1  NA   7   7  NA  NA
3          1      3   3   3  NA  11  NA  NA
4          1      4   3   3  11  NA  NA  NA
5          2      1  NA   1  16  NA  NA  NA
6          2      2   3  NA   1  NA  NA  NA
7          2      3  15   3  NA  NA  NA  NA
8          3      1  NA  18  NA  NA  NA  NA
9          3      2  18  NA  NA  NA  NA  NA
10         4      1  NA  NA  NA  NA  NA  NA
11         5      1  NA   9  NA  NA  NA  NA
12         5      2   5  NA  NA  NA  NA  NA

示例代码

df <- data.frame(household = c(1,1,1,1,2,2,2,3,3,4,5,5),
                 person = c(1,2,3,4,1,2,3,1,2,1,1,2),
                 R01 = c(NA, 1, 3, 3, NA, 3, 15, NA, 18, NA, NA, 5),
                 R02 = c(NA, NA, 3, 3, NA, NA, 3, rep(NA, 5)),
                 R03 = c(rep(NA,3), 11, rep(NA, 8)),
                 R04 = rep(NA, 12),
                 R05 = rep(NA, 12),
                 R06 = rep(NA, 12))

我知道可以编写一个函数来进行矩阵匹配,然后使用 dplyr 将其应用于每个家庭,但是我还不擅长函数,所以我 运行解决几个方面的问题。

这是一种主要使用 base R 的方法。

首先,创建 f,一个用 matching 值替换矩阵上三角的函数 rel 向量和同一矩阵的下三角。

然后,split你的数据根据​​家庭,计算每组的长度,使得到的矩阵具有正确的列数,然后将函数应用于每组。最后用原数据集bind_rowscbind

f <- function(m) {
  m[upper.tri(m)] <- match(t(m)[upper.tri(m)], rel)
  m
}

l <- split(df[3:6], df$household)
len <- lapply(l, \(l) ncol(l) - (sum(sapply(l, \(x) any(!is.na(x)))) + 1))
l <- mapply(\(x, y) x[1:(length(x) - y)], l, len, SIMPLIFY = F)

cbind(df[1:2],
      dplyr::bind_rows(lapply(l, f)))

输出

   household person R01 R02 R03 R04
1          1      1  NA   1   7   7
2          1      2   1  NA   7   7
3          1      3   3   3  NA  11
4          1      4   3   3  11  NA
5          2      1  NA   7  16  NA
6          2      2   3  NA   7  NA
7          2      3  15   3  NA  NA
8          3      1  NA  18  NA  NA
9          3      2  18  NA  NA  NA
10         4      1  NA  NA  NA  NA
11         5      1  NA   9  NA  NA
12         5      2   5  NA  NA  NA

可以让每个household中的关系矩阵对称,同时根据rel重新编码元素。

library(dplyr)

df %>%
  group_by(household) %>%
  group_modify(~ {
    mat <- as.matrix(.x[-1][1:nrow(.x)])
    mat[upper.tri(mat)] <- recode(t(mat)[upper.tri(mat)], !!!rel)
    cbind(.x[1], mat)
  }) %>% 
  ungroup()

# A tibble: 12 × 6
   household person   R01   R02   R03   R04
       <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl>
 1         1      1    NA     1     7     7
 2         1      2     1    NA     7     7
 3         1      3     3     3    NA    11
 4         1      4     3     3    11    NA
 5         2      1    NA     7    16    NA
 6         2      2     3    NA     7    NA
 7         2      3    15     3    NA    NA
 8         3      1    NA    18    NA    NA
 9         3      2    18    NA    NA    NA
10         4      1    NA    NA    NA    NA
11         5      1    NA     9    NA    NA
12         5      2     5    NA    NA    NA