我正在将数据行分配给几个不同的组。 主要问题是有许多组,但并非每个组都使用相同的字段集。 我想设置一个引用表,我可以循环或推过一个函数,但我不知道如何从过滤器中删除不需要的字段。
下面是示例代码,我提供了当前解决方案的一个版本以及一个示例表。
library(data.table)
set.seed(1)
n <- 1000
#Sample Data
ExampleData <- data.table(sample(1:3,n,replace = TRUE),
sample(10:12,n,replace = TRUE),
sample(letters[1:3],n,replace = TRUE),
sample(LETTERS[1:3],n,replace = TRUE))
#Current solution
ExampleData[V1 == 1 & V2 == 11 & V4 == "C", Group := "Group1"]
ExampleData[V1 == 2, Group := "Group2"]
ExampleData[V1 == 3 & V3 == "a" & V4 == "B", Group := "Group3"]
#Example reference table
ExampleRefTable <- data.table(Group = c("Group1","Group2","Group3"),
V1 = c(1,2,3),
V2 = c(11,NA,NA),
V3 = c(NA,NA,"a"),
V4 = c("C",NA,"B"))
(感谢@eddi:) 您可以使用by=
遍历 ref 表中的行/组:
ExampleRefTable[,
ExampleData[copy(.SD), on = names(.SD)[!is.na(.SD)], grp := .BY$Group]
, by = Group]
对于每个组,我们使用.SD
(ref 表的其余S
ubsetD
ata)进行更新连接,忽略 NA 的.SD
列。.BY
包含by=
的每个组值。
(我最初的答案:) 您可以将 ref 表拆分为具有非 NA 值的子集:
ExampleRefTable[, gNA := .GRP, by=ExampleRefTable[, !"Group"]]
RefTabs = lapply(
split(ExampleRefTable, by="gNA", keep.by = FALSE),
FUN = Filter, f = function(x) !anyNA(x)
)
看起来像
$`1`
Group V1 V2 V4
1: Group1 1 11 C
$`2`
Group V1
1: Group2 2
$`3`
Group V1 V3 V4
1: Group3 3 a B
然后使用更新联接循环访问这些表:
ExampleData[, Group := NA_character_]
for (i in seq_along(RefTabs)){
RTi = RefTabs[[i]]
nmi = setdiff(names(RTi), "Group")
ExampleData[is.na(Group), Group :=
RTi[copy(.SD), on=names(.SD), x.Group]
, .SDcols=nmi][]
}
rm(RTi, nmi)
通过过滤is.na(Group)
,我假设 ref 表中的规则是互斥的。
由于未解决的问题,需要.SD
上的copy
。
如果有许多组共享相同的缺失/非缺失列,这可能比@eddi的方式(在此答案的顶部)更有效。
如果您正在手动编写参考表,我建议...
rbindlist(idcol = "Group", fill = TRUE, list(
NULL = list(V1 = numeric(), V2 = numeric(), V3 = character(), V4 = character()),
Group1 = list(V1 = 1, V2 = 11, V4 = "C"),
Group2 = list(V1 = 2),
Group3 = list(V1 = 3, V3 = "a", V4 = "B")
))
Group V1 V2 V3 V4
1: Group1 1 11 <NA> C
2: Group2 2 NA <NA> <NA>
3: Group3 3 NA a B
以便于阅读和编辑。
如果条件正确,我们可以遍历参考数据框并将其与示例数据分配组进行比较,这可以使用任何大小的参考表和数据进行缩放,尽管如果数据>~100k,您可能希望对某些内容进行矢量化:
lenC<-ncol(ExampleRefTable)
lenT<-nrow(ExampleRefTable)
lenDat<-nrow(ExampleData)
ExampleData$Group<-"NA"
for(i in 1:lenT){
iter=i
Group_Assign<-ExampleRefTable[i,1]
Vals<-ExampleRefTable[iter,2:lenC]
for(i in 1:lenDat){
LogicArray<-ExampleData[i,1:4]==Vals
if(all(LogicArray, na.rm=T)==T){
ExampleData[i]$Group<-Group_Assign
}else{
}
}
}
> ExampleData
V1 V2 V3 V4 Group
1: 1 11 c C Group1
2: 2 12 c B Group2
3: 2 11 c A Group2
4: 3 12 b B NA
5: 1 10 a C NA
---
996: 3 12 a B Group3
997: 2 10 a C Group2
998: 1 10 a A NA
999: 1 10 a B NA
1000: 1 11 b C Group1
此示例假设参考数据中的 NA 可以与示例数据中的任何值匹配,只要位置正确,例如:
#This is assigned Group1 since NA in the ref.table matched c in pos.3
> ExampleRefTable
V1 V2 V3 V4 Group
1: 1 11 NA C Group1
> ExampleData
V1 V2 V3 V4 Group
1: 1 11 c C Group1
如果 NA 应该仅与 NA 值匹配(示例数据中没有这些值),您将更改以下代码:
for(i in 1:lenDat){
LogicArray<-ExampleData[i,1:4]==Vals
A<-Vals
B<-ExampleData[i,1:4]
NAA<-is.na(A)
NAB<-is.na(B)
if(all(NAA==NAB)==T && all(LogicArray, na.rm=T)==T){
ExampleData[i]$Group<-Group_Assign
}else{
}
}