根据R中的多个条件查找table
Lookup table based on multiple conditions in R
谢谢你看我的问题!
我有以下关于患者在 3 项任务中表现的(虚拟)数据:
patient_df = data.frame(id = seq(1:5),
age = c(30,72,46,63,58),
education = c(11, 22, 18, 12, 14),
task1 = c(21, 28, 20, 24, 22),
task2 = c(15, 15, 10, 11, 14),
task3 = c(82, 60, 74, 78, 78))
> patient_df
id age education task1 task2 task3
1 1 30 11 21 15 82
2 2 72 22 28 15 60
3 3 46 18 20 10 74
4 4 63 12 24 11 78
5 5 58 14 22 14 78
我还有以下(虚拟)查找 table 基于年龄和教育的截止值,以将患者的表现定义为在每项任务中受损或未受损:
cutoffs = data.frame(age = rep(seq(from = 35, to = 70, by = 5), 2),
education = c(rep("<16", 8), rep(">=16",8)),
task1_cutoff = c(rep(24, 16)),
task2_cutoff = c(11,11,11,11,10,10,10,10,9,13,13,13,13,12,12,11),
task3_cutoff = c(rep(71,8), 70, rep(74,2), rep(73, 5)))
> cutoffs
age education task1_cutoff task2_cutoff task3_cutoff
1 35 <16 24 11 71
2 40 <16 24 11 71
3 45 <16 24 11 71
4 50 <16 24 11 71
5 55 <16 24 10 71
6 60 <16 24 10 71
7 65 <16 24 10 71
8 70 <16 24 10 71
9 35 >=16 24 9 70
10 40 >=16 24 13 74
11 45 >=16 24 13 74
12 50 >=16 24 13 73
13 55 >=16 24 13 73
14 60 >=16 24 12 73
15 65 >=16 24 12 73
16 70 >=16 24 11 73
我的目标是在 patient_df 中创建 3 个新变量,用二元指标指示患者在每项任务中是否受损。例如,对于 patient_df 中的 id=1,他们的年龄 <=35 且受教育程度 <16 年,因此任务 1 的截止值为 24,任务 2 的截止值为 11,截止值task3 的值为 71,因此低于这些值的分数将表示受损。
我想通过在截止数据集中引用年龄和教育相关的截止值来为每个 id 执行此操作,以便结果看起来像这样:
> goal_patient_df
id age education task1 task2 task3 task1_impaired task2_impaired task3_impaired
1 1 30 11 21 15 82 1 1 0
2 2 72 22 28 15 60 0 0 1
3 3 46 18 20 10 74 1 1 0
4 4 63 12 24 11 78 1 0 0
5 5 58 14 22 14 78 1 0 0
实际上,我的 patient_df 有 600 多个患者,并且有 7 个以上的任务,每个任务都有与年龄和教育相关的截止值,所以 'clean' 这样做的方法将不胜感激!我现在能想到的唯一选择是编写一大堆 if_else 语句或 case_whens,这对于使用我的代码的任何其他人来说都不会令人难以置信地重现:(
提前致谢!
我建议将查找 table 和 patient_df
数据框都放在长格式中。我认为这可能更容易管理多个任务。
您的 education
列是数字;因此转换为字符“<16”或“>=16”将有助于查找 table.
中的匹配
使用 fuzzy_inner_join
会将数据与查找 table 匹配,其中任务和教育完全匹配 ==
但 age
将在 age_low
和 [=18 之间=] 如果您为每个查找 table 行指定年龄范围。
最后,impaired
是通过比较来自特定任务的两个数据帧的值来计算的。
请注意输出,缺少 id
of 1,因为超出了查找 table 的年龄范围。您可以向该 table 添加更多行来解决此问题。
library(tidyverse)
library(fuzzyjoin)
cutoffs_long <- cutoffs %>%
pivot_longer(cols = starts_with("task"), names_to = "task", values_to = "cutoff_value", names_pattern = "task(\d+)") %>%
mutate(age_low = age,
age_high = age + 4) %>%
select(-age)
patient_df %>%
pivot_longer(cols = starts_with("task"), names_to = "task", values_to = "patient_value", names_pattern = "(\d+)") %>%
mutate(education = ifelse(education < 16, "<16", ">=16")) %>%
fuzzy_inner_join(cutoffs_long, by = c("age" = "age_low", "age" = "age_high", "education", "task"), match_fun = list(`>=`, `<=`, `==`, `==`)) %>%
mutate(impaired = +(patient_value < cutoff_value))
输出
# A tibble: 12 x 11
id age education.x task.x patient_value education.y task.y cutoff_value age_low age_high impaired
<int> <dbl> <chr> <chr> <dbl> <chr> <chr> <dbl> <dbl> <dbl> <int>
1 2 72 >=16 1 28 >=16 1 24 70 74 0
2 2 72 >=16 2 15 >=16 2 11 70 74 0
3 2 72 >=16 3 60 >=16 3 73 70 74 1
4 3 46 >=16 1 20 >=16 1 24 45 49 1
5 3 46 >=16 2 10 >=16 2 13 45 49 1
6 3 46 >=16 3 74 >=16 3 74 45 49 0
7 4 63 <16 1 24 <16 1 24 60 64 0
8 4 63 <16 2 11 <16 2 10 60 64 0
9 4 63 <16 3 78 <16 3 71 60 64 0
10 5 58 <16 1 22 <16 1 24 55 59 1
11 5 58 <16 2 14 <16 2 10 55 59 0
12 5 58 <16 3 78 <16 3 71 55 59 0
谢谢你看我的问题!
我有以下关于患者在 3 项任务中表现的(虚拟)数据:
patient_df = data.frame(id = seq(1:5),
age = c(30,72,46,63,58),
education = c(11, 22, 18, 12, 14),
task1 = c(21, 28, 20, 24, 22),
task2 = c(15, 15, 10, 11, 14),
task3 = c(82, 60, 74, 78, 78))
> patient_df
id age education task1 task2 task3
1 1 30 11 21 15 82
2 2 72 22 28 15 60
3 3 46 18 20 10 74
4 4 63 12 24 11 78
5 5 58 14 22 14 78
我还有以下(虚拟)查找 table 基于年龄和教育的截止值,以将患者的表现定义为在每项任务中受损或未受损:
cutoffs = data.frame(age = rep(seq(from = 35, to = 70, by = 5), 2),
education = c(rep("<16", 8), rep(">=16",8)),
task1_cutoff = c(rep(24, 16)),
task2_cutoff = c(11,11,11,11,10,10,10,10,9,13,13,13,13,12,12,11),
task3_cutoff = c(rep(71,8), 70, rep(74,2), rep(73, 5)))
> cutoffs
age education task1_cutoff task2_cutoff task3_cutoff
1 35 <16 24 11 71
2 40 <16 24 11 71
3 45 <16 24 11 71
4 50 <16 24 11 71
5 55 <16 24 10 71
6 60 <16 24 10 71
7 65 <16 24 10 71
8 70 <16 24 10 71
9 35 >=16 24 9 70
10 40 >=16 24 13 74
11 45 >=16 24 13 74
12 50 >=16 24 13 73
13 55 >=16 24 13 73
14 60 >=16 24 12 73
15 65 >=16 24 12 73
16 70 >=16 24 11 73
我的目标是在 patient_df 中创建 3 个新变量,用二元指标指示患者在每项任务中是否受损。例如,对于 patient_df 中的 id=1,他们的年龄 <=35 且受教育程度 <16 年,因此任务 1 的截止值为 24,任务 2 的截止值为 11,截止值task3 的值为 71,因此低于这些值的分数将表示受损。
我想通过在截止数据集中引用年龄和教育相关的截止值来为每个 id 执行此操作,以便结果看起来像这样:
> goal_patient_df
id age education task1 task2 task3 task1_impaired task2_impaired task3_impaired
1 1 30 11 21 15 82 1 1 0
2 2 72 22 28 15 60 0 0 1
3 3 46 18 20 10 74 1 1 0
4 4 63 12 24 11 78 1 0 0
5 5 58 14 22 14 78 1 0 0
实际上,我的 patient_df 有 600 多个患者,并且有 7 个以上的任务,每个任务都有与年龄和教育相关的截止值,所以 'clean' 这样做的方法将不胜感激!我现在能想到的唯一选择是编写一大堆 if_else 语句或 case_whens,这对于使用我的代码的任何其他人来说都不会令人难以置信地重现:(
提前致谢!
我建议将查找 table 和 patient_df
数据框都放在长格式中。我认为这可能更容易管理多个任务。
您的 education
列是数字;因此转换为字符“<16”或“>=16”将有助于查找 table.
使用 fuzzy_inner_join
会将数据与查找 table 匹配,其中任务和教育完全匹配 ==
但 age
将在 age_low
和 [=18 之间=] 如果您为每个查找 table 行指定年龄范围。
最后,impaired
是通过比较来自特定任务的两个数据帧的值来计算的。
请注意输出,缺少 id
of 1,因为超出了查找 table 的年龄范围。您可以向该 table 添加更多行来解决此问题。
library(tidyverse)
library(fuzzyjoin)
cutoffs_long <- cutoffs %>%
pivot_longer(cols = starts_with("task"), names_to = "task", values_to = "cutoff_value", names_pattern = "task(\d+)") %>%
mutate(age_low = age,
age_high = age + 4) %>%
select(-age)
patient_df %>%
pivot_longer(cols = starts_with("task"), names_to = "task", values_to = "patient_value", names_pattern = "(\d+)") %>%
mutate(education = ifelse(education < 16, "<16", ">=16")) %>%
fuzzy_inner_join(cutoffs_long, by = c("age" = "age_low", "age" = "age_high", "education", "task"), match_fun = list(`>=`, `<=`, `==`, `==`)) %>%
mutate(impaired = +(patient_value < cutoff_value))
输出
# A tibble: 12 x 11
id age education.x task.x patient_value education.y task.y cutoff_value age_low age_high impaired
<int> <dbl> <chr> <chr> <dbl> <chr> <chr> <dbl> <dbl> <dbl> <int>
1 2 72 >=16 1 28 >=16 1 24 70 74 0
2 2 72 >=16 2 15 >=16 2 11 70 74 0
3 2 72 >=16 3 60 >=16 3 73 70 74 1
4 3 46 >=16 1 20 >=16 1 24 45 49 1
5 3 46 >=16 2 10 >=16 2 13 45 49 1
6 3 46 >=16 3 74 >=16 3 74 45 49 0
7 4 63 <16 1 24 <16 1 24 60 64 0
8 4 63 <16 2 11 <16 2 10 60 64 0
9 4 63 <16 3 78 <16 3 71 60 64 0
10 5 58 <16 1 22 <16 1 24 55 59 1
11 5 58 <16 2 14 <16 2 10 55 59 0
12 5 58 <16 3 78 <16 3 71 55 59 0