我正在尝试在R中创建一个函数,该函数返回一个数据框列表,这些数据框是按每个因子级别进行子集划分的。
这里有一个例子来帮助解释我想要做的事情:
#创建一个用于示例的数据集
f1<-c("a","a","b","b","c","c")
f2<-c("x","y","x","y","x","y")
v1<-c(1:6)
v2<-c(7:12)
factors<-as.data.frame(cbind(f1,f2))
integers<-as.data.frame(cbind(v1,v2))
df<-cbind(factors,integers)
#函数
partition<-function(data){
factors<-Filter(is.factor,data)
#将数据按因子分开
subsets<-list(NULL) #创建一个空列表,用于存放子集
nm=0
for( i in 1:ncol(factors)){
nm=nm+nlevels(factors[,i])
}
nm
for( i in 1:ncol(factors)){
for(j in 1:nlevels(factors[,i])){
for(k in 1:nm){
subsets[[k]]<-df[which(factors[,i]==levels(factors[,i])[j]), ]
}
}
}
return(subsets)
}
partition(df)
这会产生以下结果:
[[1]]
f1 f2 v1 v2
2 a y 2 8
4 b y 4 10
6 c y 6 12
[[2]]
f1 f2 v1 v2
2 a y 2 8
4 b y 4 10
6 c y 6 12
[[3]]
f1 f2 v1 v2
2 a y 2 8
4 b y 4 10
6 c y 6 12
[[4]]
f1 f2 v1 v2
2 a y 2 8
4 b y 4 10
6 c y 6 12
[[5]]
f1 f2 v1 v2
2 a y 2 8
4 b y 4 10
6 c y 6 12
如您所见,这些都是相同的数据集。通过移除k的循环,所有数据集都是不同的,并且正确地进行了子集划分,但它只给我提供了三个数据集(因为最后一个因子变量有两个级别,我们保留了f1 == "c"
的子集)。
移除k的for循环后,我们得到:
[[1]]
f1 f2 v1 v2
1 a x 1 7
3 b x 3 9
5 c x 5 11
[[2]]
f1 f2 v1 v2
2 a y 2 8
4 b y 4 10
6 c y 6 12
[[3]]
f1 f2 v1 v2
5 c x 5 11
6 c y 6 12
在这里,我们缺少了f1 == "a"
和f1 == "b"
的子集
请注意,我应该得到5个数据框,因为我们有2 + 3个因子级别(这是在子集划分前的第一个for循环中计算为nm
的)。
所以我的问题是,如何在不覆盖已子集划分的内容的情况下运行上述代码?
作为背景知识,这是为了创建一个分类模型,其中将产生nfactor(df)
个预测,然后我将运行一个GLM来加权每个预测。
感谢您对我的问题的任何见解。
更新Glen的第一个回答简化了我的代码,这可能使我遇到的问题更加明显。这是更新后的代码(请注意,使用split()
函数在处理大型数据集时运行得更加有效,所以感谢Glen)。
for(k in 1:nm){
for( i in 1:ncol(factors)){
for( j in 1:nlevels(factors[,i])){
subsets[[k]]<-split(df,factors[,i])[j]
}
}
}
返回的结果与我的原始问题相同。问题在于,当我通过nm对k进行循环时,循环会覆盖已经生成的内容。我如何阻止这种情况发生?
回答:
如果我正确理解了您的问题。您可以使用split函数非常轻松地做到这一点。
f1<-c("a","a","b","b","c","c")
f2<-c("x","y","x","y","x","y")
v1<-c(1:6)
v2<-c(7:12)
factors<-as.data.frame(cbind(f1,f2))
integers<-as.data.frame(cbind(v1,v2))
df<-cbind(factors,integers)
tmp1=split(df,f1)
tmp2=split(df,f2)
c(tmp1,tmp2)