从 R 中的双单声关系数据帧派生第三方亲属关系



我有一个表格显示双声部亲属关系。换句话说,我可能第一行显示一个有儿子的父亲的记录,在下一行,这个儿子显示他与父亲的关系。但是,父亲可能有另一个儿子(儿子2),所以我们在表中还有另外两个条目显示父亲与他的儿子2相关,儿子2与共同父亲有关。当两个儿子之间的关系没有出现在表中时,就会出现问题。没有条目显示儿子 1 是儿子 2 的兄弟,我需要从表中得出这一点。这是我的目标,表中的每个人都有一个唯一的标识符。

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

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

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

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

d) 在这里,前一个子组显示儿子 1 和儿子 2 是兄弟。同样,由于原始表中没有报告这一点,我的目的是通过在原始表中创建两条新记录来派生它,这些记录将显示 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) 之后,列表的第一个元素(我子集化 role="son")的结果可能是这样的:

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

如果有人能给出任何提示,他们将非常欢迎。

谢谢一百万!

考虑使用关系数据库,该数据库通过集成的家庭关系正确规范化您的关系,其中所需的结果只是对人员的自联接查询。

具体而言,在关系数据库(如 SQLite(免费、开源、文件级)等关系数据库(R 可以使用 RSQLite 连接到))中,在粒度级别创建具有家庭和个人之间一对多关系的以下关系。在"人">中的角色之下是整个家庭背景下的绝对(非相对)角色,例如被识别的祖父

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     |

在 DB 小提琴上查看(请务必单击"运行"以获取结果)


如果要完全保留在 R 中,请考虑构建相应的">家庭"和"人员"数据帧,并运行相同的合并和条件逻辑:

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

查看 Rextester

最新更新