从 R 中字符变量的部分匹配创建多个协变量
Creating Multiple Covariates from Partial Matches of a Character Variable in R
我有一个包含字母数字字符变量的大型数据框,特别是它包含有关品种组成的信息,我需要从中创建品种分数的协变量。
品种组成列包含 7000 多个品种组合,长度不一(即有些动物有 2 个品种,有些有 10 个)。品种始终由两个字母代码标识,该品种的分数是其后的系数除以该动物的所有品种系数之和(coeftotal)。
我正在寻找一种方法来从这个变量(品种)中获取系数,并使协变量对应于 7 个特定品种(SU、DP、RV、RI、CD、PO、HA)的比例。数据中存在更多的品种代码,一些动物甚至可能有 none 个感兴趣的品种。数据框包含超过 100 万条记录,我无法找到解决我的问题的有效解决方案,该解决方案不涉及针对每个特定品种代码和每个感兴趣系数(例如 SU1)的无数 grepl /if else 语句至 SUx)。此外,由于系数之和不等于相同的数,问题变得复杂。下面是我的数据框和所需输出的示例。任何想法表示赞赏!
id <- c(1:8)
breed <- c("SU1","DP1RI1","DP1RI1RV1SU1","DP3XX1","SU9RV7","XX1","DP7XX1","SU32RV16DP8RI8")
sheep <- data.frame(id,breed)
id breed coeftot SU DP RV RI CD PO HA
1 SU1 1 1 0 0 0 0 0 0
2 DP1RI1 2 0 0.5 0 0.5 0 0 0
3 DP1RI1RV1SU1 4 0.25 0.25 0.25 0.25 0 0 0
4 DP3XX1 4 0 0.75 0 0 0 0 0
5 SU9RV7 16 0.5625 0 0.4375 0 0 0 0
6 XX1 1 0 0 0 0 0 0 0
7 DP7XX1 8 0.875 0 0 0 0 0 0
8 SU32RV16DP8RI8 64 0.5 0.125 0.25 0.125 0 0 0
如果您需要内存和速度效率,data.table
包很好。 stringi
对字符串操作有很大帮助。
library(stringi)
breed_codes <- unique(unlist(stri_extract_all_regex(
sheep[["breed"]], "[A-Z]+"
)))
breed_codes
# "SU" "DP" "RI" "RV" "XX"
patterns <- sprintf("(?<=%s)\d+", breed_codes)
patterns
# "(?<=SU)\d+" "(?<=DP)\d+" "(?<=RI)\d+" "(?<=RV)\d+" "(?<=XX)\d+"
首先我们使用正则表达式提取受试者品种集中的所有品种代码,这些代码是连续的大写字母([A-Z]+
)。接下来,我们将创建一个正则表达式来捕获它们中的每一个的系数。
我们想要捕获每个品种代码 ((?<=SU)
) 前面的任意数量的数字 (\d+
)。我们将遍历每个品种并使用模式捕获的数字为其分配一列。如果受试者的品种集没有代码,那么我们将其设置为 0。
library(data.table)
setDT(sheep)
set(
sheep,
j = breed_codes,
value = lapply(
patterns,
function(pat) {
digits <- stri_extract_first_regex(sheep[["breed"]], pat)
digits[is.na(digits)] <- "0"
breed_coef <- as.integer(digits)
breed_coef
}
)
)
最后,我们将每一行的系数相加作为总和。
sheep[, coeftot := rowSums(.SD), .SDcols = breed_codes]
如果您想将特定七种以外的品种合并到一个 "other" 列中,那么我们只需识别它们,按行对它们求和,然后将它们从数据集中删除。
special_breeds <- c("SU", "DP", "RV", "RI", "CD", "PO", "HA")
non_special_breeds <- setdiff(breed_codes, special_breeds)
sheep[, other := rowSums(.SD), .SDcols = non_special_breeds]
set(sheep, j = non_special_breeds, value = NULL)
sheep
# id breed SU DP RI RV coeftot other
# 1: 1 SU1 1 0 0 0 1 0
# 2: 2 DP1RI1 0 1 1 0 2 0
# 3: 3 DP1RI1RV1SU1 1 1 1 1 4 0
# 4: 4 DP3XX1 0 3 0 0 4 1
# 5: 5 SU9RV7 9 0 0 7 16 0
# 6: 6 XX1 0 0 0 0 1 1
# 7: 7 DP7XX1 0 7 0 0 8 1
# 8: 8 SU32RV16DP8RI8 32 8 8 16 64 0
我有一个包含字母数字字符变量的大型数据框,特别是它包含有关品种组成的信息,我需要从中创建品种分数的协变量。
品种组成列包含 7000 多个品种组合,长度不一(即有些动物有 2 个品种,有些有 10 个)。品种始终由两个字母代码标识,该品种的分数是其后的系数除以该动物的所有品种系数之和(coeftotal)。
我正在寻找一种方法来从这个变量(品种)中获取系数,并使协变量对应于 7 个特定品种(SU、DP、RV、RI、CD、PO、HA)的比例。数据中存在更多的品种代码,一些动物甚至可能有 none 个感兴趣的品种。数据框包含超过 100 万条记录,我无法找到解决我的问题的有效解决方案,该解决方案不涉及针对每个特定品种代码和每个感兴趣系数(例如 SU1)的无数 grepl /if else 语句至 SUx)。此外,由于系数之和不等于相同的数,问题变得复杂。下面是我的数据框和所需输出的示例。任何想法表示赞赏!
id <- c(1:8)
breed <- c("SU1","DP1RI1","DP1RI1RV1SU1","DP3XX1","SU9RV7","XX1","DP7XX1","SU32RV16DP8RI8")
sheep <- data.frame(id,breed)
id breed coeftot SU DP RV RI CD PO HA
1 SU1 1 1 0 0 0 0 0 0
2 DP1RI1 2 0 0.5 0 0.5 0 0 0
3 DP1RI1RV1SU1 4 0.25 0.25 0.25 0.25 0 0 0
4 DP3XX1 4 0 0.75 0 0 0 0 0
5 SU9RV7 16 0.5625 0 0.4375 0 0 0 0
6 XX1 1 0 0 0 0 0 0 0
7 DP7XX1 8 0.875 0 0 0 0 0 0
8 SU32RV16DP8RI8 64 0.5 0.125 0.25 0.125 0 0 0
如果您需要内存和速度效率,data.table
包很好。 stringi
对字符串操作有很大帮助。
library(stringi)
breed_codes <- unique(unlist(stri_extract_all_regex(
sheep[["breed"]], "[A-Z]+"
)))
breed_codes
# "SU" "DP" "RI" "RV" "XX"
patterns <- sprintf("(?<=%s)\d+", breed_codes)
patterns
# "(?<=SU)\d+" "(?<=DP)\d+" "(?<=RI)\d+" "(?<=RV)\d+" "(?<=XX)\d+"
首先我们使用正则表达式提取受试者品种集中的所有品种代码,这些代码是连续的大写字母([A-Z]+
)。接下来,我们将创建一个正则表达式来捕获它们中的每一个的系数。
我们想要捕获每个品种代码 ((?<=SU)
) 前面的任意数量的数字 (\d+
)。我们将遍历每个品种并使用模式捕获的数字为其分配一列。如果受试者的品种集没有代码,那么我们将其设置为 0。
library(data.table)
setDT(sheep)
set(
sheep,
j = breed_codes,
value = lapply(
patterns,
function(pat) {
digits <- stri_extract_first_regex(sheep[["breed"]], pat)
digits[is.na(digits)] <- "0"
breed_coef <- as.integer(digits)
breed_coef
}
)
)
最后,我们将每一行的系数相加作为总和。
sheep[, coeftot := rowSums(.SD), .SDcols = breed_codes]
如果您想将特定七种以外的品种合并到一个 "other" 列中,那么我们只需识别它们,按行对它们求和,然后将它们从数据集中删除。
special_breeds <- c("SU", "DP", "RV", "RI", "CD", "PO", "HA")
non_special_breeds <- setdiff(breed_codes, special_breeds)
sheep[, other := rowSums(.SD), .SDcols = non_special_breeds]
set(sheep, j = non_special_breeds, value = NULL)
sheep
# id breed SU DP RI RV coeftot other
# 1: 1 SU1 1 0 0 0 1 0
# 2: 2 DP1RI1 0 1 1 0 2 0
# 3: 3 DP1RI1RV1SU1 1 1 1 1 4 0
# 4: 4 DP3XX1 0 3 0 0 4 1
# 5: 5 SU9RV7 9 0 0 7 16 0
# 6: 6 XX1 0 0 0 0 1 1
# 7: 7 DP7XX1 0 7 0 0 8 1
# 8: 8 SU32RV16DP8RI8 32 8 8 16 64 0