从R中的生物单相关系数据框架中获得第三方亲属关系

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

我有一张表显示双向一致的亲属关系。换句话说,我可能有第一行显示有父亲的儿子的记录,在下一行中,这个儿子显示他与父亲的关系。但是,父亲可能有另一个儿子(son2),所以我们在表格中有另外两个条目,显示父亲与他的儿子2相关,而儿子2与普通父亲相关联。当两个儿子之间的关系没有出现在表格中时,问题就出现了。没有条目显示son1是son2的兄弟,我需要从表中派生出来。这是我的目标,表中的每个人都有一个唯一的标识符。

到目前为止,我一直在尝试做的是:

a)创建所有可能的亲属角色的列表(在上面的简化示例中,只有2个角色:父亲和儿子)。

b)将原始表子集合到与角色一样多的组中。由于我的例子中的任何个人都可能是儿子和/或父亲,我创建了两组数据。这些组是列表的元素,因此,换句话说,我通过对记录的角色进行子集来创建列表。在这个例子中,列表有两个元素:一个用于第二个人是第一个人的儿子的记录,另一个元素显示第二个人是第一个人的父亲的条目。

c)我的想法也是按照第一个人的ID对列表的前两个元素进行子集化。这样,我的目标是创建具有所有关系的每个给定ID的组。例如,在我们的例子中,我们将获得一个由两行组成的ID(父亲)的组:son1和son2的记录。

d)在这里,前一个子组显示son1和son2是兄弟。再次,原始表中没有报告这个,我的目的是通过编码在原始表中创建两个新记录来导出它,这将显示son1有一个兄弟son2,而son2有一个兄弟son1。

鉴于我的数据帧是df并且关系中第二个人的变量角色是Role_2nd,步骤a)很简单:

role <- unique(df$Role_2nd)

步骤b)也很容易:

newRoles <- lapply(role, function(x){subset(df, Role_2nd == x)})

在步骤c)之后,列表的第一个元素 - 我的子集角色=“儿子” - 的结果可能是这样的:

ID_First  ID_Second    Role_1st      Role_2nd
569         571          father        son
590         592          father        son
587         597          father        son
597         596          father        son
597         598          father        son
603         604          father        son
603         607          father        son 

我们可以看到,ID 597有两个儿子(596和598)。这意味着596和598是兄弟姐妹,我需要得出原始表中不存在的这种关系。

在步骤d)之后,按ID进行子集化:

ID_First  ID_Second    Role_1st      Role_2nd
569         571          father        son

ID_First  ID_Second    Role_1st      Role_2nd
590         592          father        son

ID_First  ID_Second    Role_1st      Role_2nd
587         597          father        son

ID_First  ID_Second    Role_1st      Role_2nd
597         596          father        son
597         598          father        son

ID_First  ID_Second    Role_1st      Role_2nd
603         604          father        son
603         607          father        son 

(可能,步骤d)对我的最终目标来说是可有可无的)。

在示例之后,列表的另一个元素 - 作为Role_2nd-的父亲的元素应该是这样的:

Step c)

ID_First   ID_Second       Role_1st       Role_2nd
571          569              son          father
592          590              son          father
597          587              son          father
596          597              son          father
598          597              son          father
604          603              son          father
607          603              son          father


I skip showing step d) also for the second element.

现在,这就是我所坚持的。如果以上所有都是正确的 - 可能有更简单的方法来解决问题 - 鉴于我想创建我的原始表中不存在的角色“兄弟”,我的想法是通过一个运行列表的两个元素环。从第一个开始,每当我发现重复的ID_First(发生在597和603)时,那就意味着他们联系到的两个人(一方面是-596和598,另一方面是604& 607-)必须是“兄弟”。

但我不知道该怎么做。我不知道如何在列表的元素中发现变量的几个相等值(比如在列表的第一个元素中发现两个或多个相等的ID_First);我不知道如何将它们分组;我不知道如何为列表中每个元素的每个组件运行循环;我不知道如何以更简单的方式编写代码而不是运行无限循环(这里我只显示两个不同的角色,但在我的情况下角色的大小非常大 - 我正在工作与“非西方”的血缘关系 - )。

总结一下,我的问题的最终结果将是这样的:

ID_First   ID_Second       Role_1st       Role_2nd
596          597              son          father
598          597              son          father
596          598            brother        brother
598          596            brother        brother
604          603              son          father
607          603              son          father
604          607            brother        brother
607          604            brother        brother

如果有人可以提供任何提示,他们将非常欢迎。

太感谢了!

r list loops apply
1个回答
0
投票

考虑使用一个关系数据库,该关系数据库可以正确地规范您与集成的Families关系的关系,其中您想要的结果只是对Persons的self-join查询。

具体来说,在关系数据库(如SQL可以使用RSQLite连接的SQLite(免费,开源,文件级))中以粒度级别创建以下关系,以及Families和Persons之间的一对多关系。人物角色的下方是整个家庭背景中的绝对(非相对)角色,例如祖父被识别。

CREATE TABLE Families (
  ID INTEGER,
  FAMILY_NAME VARCHAR(50)
);

CREATE TABLE Persons (
  ID INTEGER,
  FAM_ID INTEGER,
  Role VARCHAR(50),
  FOREIGN KEY(FAM_ID) REFERENCES Family(ID)  
);


INSERT INTO Families
VALUES (1, 'Alpha'), (2, 'Bravo'), (3, 'Charlie'), (4, 'Delta');

INSERT INTO Persons
VALUES(569, 1, 'father'),
      (590, 2, 'father'),
      (587, 3, 'grandfather'),
      (597, 3, 'father'),
      (603, 4, 'father'),
      (571, 1, 'son'),
      (592, 2, 'son'),
      (597, 3, 'son'),
      (596, 3, 'son'),
      (598, 3, 'son'),
      (604, 4, 'son'),
      (607, 4, 'son');

然后使用条件逻辑运行以下查询来分配兄弟:

SELECT p1.ID AS ID1, p2.ID AS ID2,
       CASE 
            WHEN p1.Role = 'son' AND p2.Role = 'son'
            THEN 'brother'
            ELSE p1.Role
       END As Role1,

       CASE 
            WHEN p1.Role = 'son' AND p2.Role = 'son'
            THEN 'brother'
            ELSE p2.Role
       END As Role2

FROM Persons p1
INNER JOIN Persons p2 ON p1.FAM_ID = p2.FAM_ID AND p1.ID > p2.ID

ORDER BY p1.ID, p2.ID;

-- | ID1 | ID2 | Role1   | Role2       |
-- | --- | --- | ------- | ----------- |
-- | 571 | 569 | son     | father      |
-- | 592 | 590 | son     | father      |
-- | 596 | 587 | son     | grandfather |
-- | 597 | 587 | father  | grandfather |
-- | 597 | 587 | son     | grandfather |
-- | 597 | 596 | father  | son         |
-- | 597 | 596 | brother | brother     |
-- | 598 | 587 | son     | grandfather |
-- | 598 | 596 | brother | brother     |
-- | 598 | 597 | son     | father      |
-- | 598 | 597 | brother | brother     |
-- | 604 | 603 | son     | father      |
-- | 607 | 603 | son     | father      |
-- | 607 | 604 | brother | brother     |

View on DB Fiddle(一定要点击Run for results)


如果您想完全保留在R中,请考虑构建相应的Families和Persons数据框并运行相同的合并和条件逻辑:

建立

Families <- data.frame(ID = seq(1, 4),
                       Family_Name = c("Alpha", "Bravo", "Charlie", "Delta"))

Persons <- data.frame(ID = c(569, 590, 587, 597, 603, 571, 592, 597, 596, 598, 604, 607),
                      Fam_ID = c(1, 2, 3, 3, 4, 1, 2, 3, 3, 3, 4, 4),
                      Role = c("father", "father", "grandfather", "father", "father",
                               "son", "son", "son", "son", "son", "son", "son"))

询问

# SELF JOIN, AVOIDING REVERSE DUPLICATES
merge_raw <- subset(merge(Persons, Persons, by="Fam_ID", suffixes = c("_1", "_2")), 
                    ID_1 > ID_2) 

# CONDITIONALLY ASSIGN "brother"
final_df <- within(merge_raw, {    
        ID_1 <- ifelse(ID_1 == "son" & ID_2 == "son", "brother", ID_1)
        ID_2 <- ifelse(ID_1 == "son" & ID_2 == "son", "brother", ID_2)
    })

# RE-ORDER ROWS AND COLUMNS
final_df <- with(final_df, data.frame(final_df[order(ID_1, ID_2), 
                                               c("ID_1", "ID_2", "Role_1", "Role_2")],
                                      row.names = NULL))

final_df

#    ID_1 ID_2 Role_1      Role_2
# 1   571  569    son      father
# 2   592  590    son      father
# 3   596  587    son grandfather
# 4   597  587 father grandfather
# 5   597  587    son grandfather
# 6   597  596 father         son
# 7   597  596    son         son
# 8   598  587    son grandfather
# 9   598  596    son         son
# 10  598  597    son      father
# 11  598  597    son         son
# 12  604  603    son      father
# 13  607  603    son      father
# 14  607  604    son         son

View on Rextester

© www.soinside.com 2019 - 2024. All rights reserved.