自定义R函数返回奇怪的输出

时间:2013-12-04 22:17:04

标签: r functional-programming lapply

所以我试图创建一个数据框列表,主要是为了通过mclapply将它们传递给多个核心。但那不是我遇到麻烦的部分。我编写了一个函数来从一个大数据帧创建一个较小数据帧的列表,然后按顺序应用它以将大数据帧分解为一个小数据帧列表。问题是当第二次调用该函数时(通过lapply到第一个数据帧列表),它会向更大列表中的每个数据帧列表添加额外的小数据帧。我不知道为什么。我不认为这是lapply,因为当我从第一个列表中的一个帧上手动运行该函数时,它也可以工作。这是代码:

create_frame_list<-function(mydata,mystep,elnames){

    datalim<-dim(mydata)[1]
    mylist<-list()
    init<-1
    top<-mystep
    i<-1

    repeat{

        if(top < datalim){
            mylist[[i]]<-assign(paste(elnames,as.character(i),sep=""),data.frame(mydata[init:top,]))
            }
        else {
            mylist[[i]]<-assign(paste(elnames,as.character(i),sep=""),data.frame(mydata[init:datalim,]))
            }

        if(top > datalim){break}    

        i<-i+1
        init<-top+1
        top<-top+mystep

        }

        return(mylist)
    }

test_data<-data.frame(replicate(10,sample(0:1,1000,rep=TRUE)))

#Create the first list of data frames, works fine
master_list<-create_frame_list(test_data,300,"bd")

#check the dimensions of the data frames created, they are correct
lapply(master_list,dim)

#create a list of lists of data frames, doesn't work right
list_list<-lapply(master_list,create_frame_list,50,"children")

#check the dimensions of the data frames in the various lists. The function when called again is making extra data frames of length 2 for no reason I can see
lapply(list_list,lapply,dim)

就是这样。任何帮助都会一如既往地受到赞赏。

1 个答案:

答案 0 :(得分:1)

好的,所以你的代码只有一个小bug,但肯定有更好的方法。当行数是step的精确倍数时,您的代码不起作用。这与您break的位置有关。这是一个修复:

create_frame_list<-function(mydata,mystep,elnames){
  datalim<-dim(mydata)[1]
  mylist<-list()
  init<-1
  top<-mystep
  i<-1
  repeat{
    if(top < datalim)
      # mylist[[i]]<-assign(paste0(elnames,as.character(i)),data.frame(mydata[init:top,]))
      mylist[[i]]<-mydata[init:top,]
    else 
      mylist[[i]]<-mydata[init:datalim,]
    # if(top > datalim) break 
    i<-i+1
    init<-top+1
    top<-top+mystep
    if(init > datalim) break
  }
  return(mylist)
}

主要修复方法是移动if并使其依赖init,而不是top

您会注意到我清理了您的代码,并删除了assign声明。一个好的经验法则是:如果您认为需要使用assignget,那么您做错了。在您的情况下,分配是完全冗余的,并没有按照您想要的方式分配名称。


如果您正在寻找更好的方法,可以选择以下方法之一:

n<-nrow(test_data)
step<-300
split.var<-rep(1:ceiling(n/step),each=step,length.out=n)
master_list<-split(test_data,split.var)
names(master_list)<-paste0('bd',seq_along(master_list))
# If you didn't care about the order of the rows you could just do 
# split(test_data,seq(ceiling(n/step)))

如果你想获得幻想,你可以做类似的事情:

special.split<-function(data,step) 
  split(data,rep(1:ceiling(nrow(data)/step),each=step,length.out=nrow(data)))
lapply(special.split(test_data,300),special.split,step=50)

这样就可以一步到位。