我有一个表格显示双声部亲属关系。换句话说,我可能第一行显示一个有儿子的父亲的记录,在下一行,这个儿子显示他与父亲的关系。但是,父亲可能有另一个儿子(儿子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