我有一张表显示双向一致的亲属关系。换句话说,我可能有第一行显示有父亲的儿子的记录,在下一行中,这个儿子显示他与父亲的关系。但是,父亲可能有另一个儿子(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
如果有人可以提供任何提示,他们将非常欢迎。
太感谢了!
考虑使用一个关系数据库,该关系数据库可以正确地规范您与集成的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