【问题标题】:generate group (family) in R在 R 中生成组(家庭)
【发布时间】:2012-07-17 04:19:47
【问题描述】:

我有以下类型的数据:

Person <- c("A",  "B", "C",  "D",  "E",  "E",  "F",  "G", "H", "I")
MOM <- c(   NA,   NA,   NA,  "A",  "A",   NA,  "A",  "B", "C", NA)
DAD <- c(   NA,   NA,   NA,  "B",  "B",   NA,  "E",  "A", "B", NA)
Xv <- 1:10
myd <- data.frame (Person, MOM, DAD, Xv, stringsAsFactors=F)
myd 
       Person  MOM  DAD Xv
1       A <NA> <NA>  1
2       B <NA> <NA>  2
3       C <NA> <NA>  3
4       D    A    B  4
5       E    A    B  5
6       E <NA> <NA>  6
7       F    A    E  7
8       G    B    A  8
9       H    C    B  9
10      I <NA> <NA> 10

此数据包括 Person 及其 Mom 和 Dad 列。我想为此数据创建家庭组。 NA 是信息缺失。定义了一个具有共同 MOM 和 DAD 的家庭。创始人是那些同时拥有 NA, family = 0 的人。

这是我能想到的,这对我来说并不完美:

fun <- function(i) {
  i1 <- if (is.na(myd[i, 2])) i else match(myd[i, 2], myd[1:i, 2])
  i2 <- if (is.na(myd[i, 3])) i else match(myd[i, 3], myd[1:i, 3])
  min(i1, i2)
}
myd$family <- as.numeric(factor(sapply(1:nrow(myd), fun)))
  Person  MOM  DAD Xv family
1       A <NA> <NA>  1      1
2       B <NA> <NA>  2      2
3       C <NA> <NA>  3      3
4       D    A    B  4      4
5       E    A    B  5      4
6       E <NA> <NA>  6      5
7       F    A    E  7      4
8       G    B    A  8      6
9       H    C    B  9      4
10      I <NA> <NA> 10      7

上述功能在某种意义上是不完善的: 家庭数据不包括其父母的数据,例如家庭 4 应包括 A 和 B 的数据。因此完整的家庭看起来像:

1       A <NA> <NA>  1      1
2       B <NA> <NA>  2      2
4       D    A    B  4      4
5       E    A    B  5      4

另一件事(至少对我来说是这样),作为 DAD = A 和 MOM = B 与 DAD = B 和 MOM = A 相同。因此家庭 4 和 6 是相同的 A 和 B 父母的产物,所以应该 相同的。

4       D    A    B  4      4
5       E    A    B  5      4
8       G    B    A  8      6

因此预期的输出是:

Person  MOM  DAD Xv     family
# founders 
1       A <NA> <NA>  1      0
2       B <NA> <NA>  2      0
3       C <NA> <NA>  3      0
10      I <NA> <NA> 10      0
6       E <NA> <NA>  6      0
# Family 1
1       A <NA> <NA>  1      1
2       B <NA> <NA>  2      1
4       D    A    B  4      1
5       E    A    B  5      1
8       G    B    A  8      1
# Family 2
1       A <NA> <NA>  1      2
6       E <NA> <NA>  6      2
7       F    A    E  7      2
# Family 3
2       B <NA> <NA>  2      3
3       C <NA> <NA>  3      3
9       H    C    B  9      3

编辑:

遗憾的是(好!)在人类遗传学中,我们需要处理类似的变量——家庭、三人组、妈妈(父母 1、母亲、女性)、父亲(父亲、父母 2、男性)、个体/主体等。这使得一切相似和问题都相似。

  Family vs Trio 
  1 Nuclear family 
  A  x   B
      |
   C   D  E

  Trio -> 3 trios  
  A x B      A x B       A x B
     |         |            |
     C          D           E  

提问者的修改:我同意下面的cmets作为作业,请不要回答问题一段时间(你认为足够好的时间已经过去了作业提交时间)。如果我得到答案,我会在稍后(3 个月左右)发布。

编辑

创始人定义 - 父母双方都不知道自己是否是儿子/女儿的人,因此他们在 MOM 和 DAD 列中都有。这些被认为是家庭 0,因为它们是其他家庭的一部分,但该列表不是真正的家庭。

 Person  MOM  DAD Xv     family
    1       A <NA> <NA>  1      0
    2       B <NA> <NA>  2      0
    3       C <NA> <NA>  3      0
    10      I <NA> <NA> 10      0
    6       E <NA> <NA>  6      0

** 家庭定义* 一个家庭由父母(妈妈和爸爸)以及所有的儿子和女儿组成。如果 Person DAD and MOM 与另一个人 DAD 和 MOM 匹配,则应将其视为一个家庭。例如,以下列表中的 D 和 E 人有 MOM = A 和 DAD = B,这两个人与 D 和 E 一起组成了一个家庭。现在我们需要从创始人列表(家庭 0)中回收他们父母(A 和 B)的数据。

 # Family 1
        Person  MOM  DAD     Xv     family
    1       A <NA> <NA>  1      1
    2       B <NA> <NA>  2      1
    4       D    A    B  4      1
    5       E    A    B  5      1

另外,与这里的人类情况相反,一个人可以是 MOM 或 DAD(可以转换性别),因此 A (MOM) 和 B (DAD) 产生的后代与 B (MOM) 和 A 产生的后代相同(DAD),因此我们需要将以下个人添加到家庭 1 列表中。

       Person  MOM   DAD     Xv     family
   8       G       B    A       8      1

因此家庭 1 的完整列表变为:

     Person  MOM   DAD Xv     family
1       A <NA> <NA>  1      1
2       B <NA> <NA>  2      1
4       D    A    B  4      1
5       E    A    B  5      1
8       G    B    A  8      1

家庭 1 可以用图解表示为:

            MOM   x   DAD             MOM   x   DAD
              A  |   B        or       B  |     A 
            -----------------          ------
           |                 |           |
           D                 E           G

这里是部分解决方案:

myd1 <- data.frame(myd$DAD, myd$MOM) 
myd$family<-as.factor(apply(myd1,1,function(x){paste(x[order(x)],collapse='-')}))
   Person  MOM  DAD Xv family
1       A <NA> <NA>  1  NA-NA
2       B <NA> <NA>  2  NA-NA
3       C <NA> <NA>  3  NA-NA
4       D    A    B  4    A-B
5       E    A    B  5    A-B
6       E <NA> <NA>  6  NA-NA
7       F    A    E  7    A-E
8       G    B    A  8    A-B
9       H    C    B  9    B-C
10      I <NA> <NA> 10  NA-NA

它没有给出家族编号,而是 A 和 B 的家族。NA-NA 是创始人,它在崩溃之前下令,因此 A-B 变为 B-A。

剩下的问题是 A-B 家庭需要从人 A 和 B 回收的数据(尽管他们在家庭 NA-NA 组中)。

  Person  MOM  DAD Xv family
1       A <NA> <NA>  1  NA-NA
2       B <NA> <NA>  2  NA-NA
4       D    A    B  4    A-B
5       E    A    B  5    A-B

【问题讨论】:

  • 这个问题和stackoverflow.com/q/11513895/602276有什么不同?
  • @Andrie -- 因为它是被另一个人问的?作业?
  • @mrdwab 啊,这很有道理,不是吗?这里没什么有趣的。我继续前进。
  • @Andrie 问题是不同的,尽管变量非常相似 - 爸爸妈妈等人类需要与之合作......它需要产生家庭而不是三人......
  • @mrdwab 这不是家庭作业....我认为每个人都不要在一段时间内回答这个问题,如果你这么认为并且家庭作业时间已经过去了....所以如果我有答案,我会发布它为大家好

标签: r dataframe


【解决方案1】:

我不确定你是否已经解决了这个问题,但这里有一个解决方案。

首先,您的数据:

# Your data
myd <- data.frame(Person = c("A", "B", "C", "D", "E", 
                             "E", "F", "G", "H", "I"),
                  MOM = c(NA, NA, NA, "A", "A", NA, "A", "B", "C", NA),
                  DAD = c(NA, NA, NA, "B", "B", NA, "E", "A", "B", NA),
                  Xv = 1:10, stringsAsFactors=F)

其次,我们通过将原始数据中的第 2 列和第 3 列合并在一起来识别这些族。我们会用这个把split你的data.frame放到一个列表中。

# Identifying the families
fam = apply(myd[2:3], 1, function(x) paste0(sort(x), collapse=" "))

第三,我们将data.frame 拆分为一个列表。在这种情况下,我们最终得到一个包含四个 data.frames 的列表:一个用于创始人,一个用于每个家庭。

# Splitting the data by founders and families
temp_1 = split(myd, fam)
names(temp_1)[1] = "Founders"

第四,我们做一些简单的匹配和子集来识别哪些创始人属于哪些家族。

# Identify which families the founders belong to
temp_2 = lapply(1:length(temp_1),
                function(x) temp_1[[1]][which(temp_1[[1]]$Person %in% 
                  unique(unlist(temp_1[[x]][,c(2,3)], use.names=FALSE))),])

最后,我们rbind 将这些数据放在一起。

# "Merging" (with rbind) founders and their families
OUT = lapply(1:length(temp_1), function(x) rbind(temp_2[[x]], temp_1[[x]]))
names(OUT) = names(temp_1)

这是输出:

OUT
# $Founders
#    Person  MOM  DAD Xv
# 1       A <NA> <NA>  1
# 2       B <NA> <NA>  2
# 3       C <NA> <NA>  3
# 6       E <NA> <NA>  6
# 10      I <NA> <NA> 10
# 
# $`A B`
#   Person  MOM  DAD Xv
# 1      A <NA> <NA>  1
# 2      B <NA> <NA>  2
# 4      D    A    B  4
# 5      E    A    B  5
# 8      G    B    A  8
# 
# $`A E`
#   Person  MOM  DAD Xv
# 1      A <NA> <NA>  1
# 6      E <NA> <NA>  6
# 7      F    A    E  7
# 
# $`B C`
#   Person  MOM  DAD Xv
# 2      B <NA> <NA>  2
# 3      C <NA> <NA>  3
# 9      H    C    B  9

更新:data.frame 输出

如果您更喜欢data.frame 而不是list,您可以在完成上述步骤后执行以下操作:

OUT = do.call("rbind", 
              lapply(1:length(OUT), 
                     function(x) cbind(OUT[[x]], fam = names(OUT[x]))))
OUT
#    Person  MOM  DAD Xv      fam
# 1       A <NA> <NA>  1 Founders
# 2       B <NA> <NA>  2 Founders
# 3       C <NA> <NA>  3 Founders
# 6       E <NA> <NA>  6 Founders
# 10      I <NA> <NA> 10 Founders
# 11      A <NA> <NA>  1      A B
# 21      B <NA> <NA>  2      A B
# 4       D    A    B  4      A B
# 5       E    A    B  5      A B
# 8       G    B    A  8      A B
# 12      A <NA> <NA>  1      A E
# 61      E <NA> <NA>  6      A E
# 7       F    A    E  7      A E
# 22      B <NA> <NA>  2      B C
# 31      C <NA> <NA>  3      B C
# 9       H    C    B  9      B C

【讨论】:

    【解决方案2】:

    如果您想要每个“家庭”的字符向量都相同,那么使用interaction 函数会更紧凑。大致如下:

    myd$fam <- with( myd, as.character( interaction(MOM,DAD)))
    myd$fam[ is.na(myd$fam) ] <- 0
    

    如果您想要数字(这似乎不明智,但这就是您提出要求的方式),那么请使用 as.character 而不是 as.numeric

    myd$fam <- with( myd, as.numeric( interaction(MOM,DAD)))
    myd$fam[ is.na(myd$fam) ] <- 0
    

    我从来没有想过如何让“A”同时代表妈妈和爸爸。您可能需要解释您如何理解人类遗传学的这一方面。家庭分割请使用split

    > split(myd, myd$fam)
    $`0`
       Person  MOM  DAD Xv fam
    1       A <NA> <NA>  1   0
    2       B <NA> <NA>  2   0
    3       C <NA> <NA>  3   0
    6       E <NA> <NA>  6   0
    10      I <NA> <NA> 10   0
    
    $`2`
      Person MOM DAD Xv fam
    8      G   B   A  8   2
    
    $`4`
      Person MOM DAD Xv fam
    4      D   A   B  4   4
    5      E   A   B  5   4
    
    $`6`
      Person MOM DAD Xv fam
    9      H   C   B  9   6
    
    $`7`
      Person MOM DAD Xv fam
    7      F   A   E  7   7
    

    【讨论】:

    • 感谢您的解决方案,解决方案中唯一剩下的就是 MOM 和 DAD 在他们的家庭中代表,例如,人 G 的家庭 2 应该有来自 B 和 A 的数据(尽管它是在创始人家族 0) 中,只是重复。
    • 您需要更好地阐明“创始人”的运营定义。如果该定义依赖于在行中遇到的数据序列,那么您需要这么说。在确定男性/女性/两性人的更易理解的表示之前,我不愿意付出更多的努力。如果这确实与具有这种基因行为的物种有关,那么您需要更全面地描述该领域。
    • 我试图详细解释,请参阅我最近的编辑。我有一个部分解决方案(见编辑),谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多