【问题标题】:Custom R function returning weird output自定义 R 函数返回奇怪的输出
【发布时间】:2013-12-21 15:24:40
【问题描述】:

所以我试图创建一个数据帧列表的列表,主要是为了通过 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)

就是这样。一如既往地感谢任何帮助。

【问题讨论】:

    标签: r functional-programming lapply


    【解决方案1】:

    好的,所以您的代码只有一个小错误,但肯定有更好的方法来做到这一点。当行数是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)
    

    这样就可以一步完成。

    【讨论】:

    • 非常感谢。我曾尝试使用'split',但不是很熟悉我只是使用循环函数来完成它,因为它不是在代码上下文中经常调用的操作。感谢您的帮助。
    • 没问题,我用一种奇特的方式更新了我的答案。
    • 顺便说一句,我意识到在发布问题和您的答案之间我不需要分配语句。我不时发现它们很方便,但有时它们确实会给出奇怪的结果。我喜欢你的最后一种方式,功能越多越好。
    猜你喜欢
    • 2022-08-17
    • 1970-01-01
    • 2020-03-26
    • 2016-10-11
    • 1970-01-01
    • 1970-01-01
    • 2020-06-18
    • 2012-06-21
    • 1970-01-01
    相关资源
    最近更新 更多