在 r 中的函数内部使用 assign 时是否可以保留数据类型?

Is it possible to keep the datatype while using assign inside a function in r?

我第一次 post 在这里,如果我遗漏了任何重要信息,请告诉我。

我正在处理大量时间形式的数据(1:30=rowID)与存储在多个数据帧中的值,我需要将其保存为 data.frame。 我写了一个函数,它从我的全局环境中获取数据框,并根据它们的值将每个集合中的列排序到新的数据框中。

所以我从我的数据框的名称列表开始作为我的函数的输入,然后在使用分配函数时将创建的新数据框分配到我的全局环境结束。 我得到的所有数据框都是 30 行长,但列长不同,具体取决于案例在数据集中出现的频率。每个dataframe的名称代表一个数据集,里面的列名代表一个时间线。我使用数据框,所以我不会丢失列名的信息。

这适用于 0 个案例和大于 1 的所有案例。 但是,如果 data.frame 最终只有一列并且我使用分配函数,它在我的全局环境中显示为矢量而不是数据框。因此,我丢失了列的名称,我的其他仅使用数据帧的函数在这种情况下停止并抛出错误。

这是我的问题的一个基本示例:

#create two datasets with different cases
data1 <- data.frame(matrix(nrow=30, ncol=5))
data1[1] <- c(rep(1,each=30))
data1[2] <- c(rep(5, each=30))
data1[3] <- c(rep(5, each=30))
data1[4] <- c(rep(10, each=30))
data1[5] <- c(rep(10, each=30))

data2 <- data.frame(matrix(nrow=30, ncol=6))
data2[1] <- c(rep(5,each=30))
data2[2] <- c(rep(1, each=30))
data2[3] <- c(rep(1, each=30))
data2[4] <- c(rep(0, each=30))
data2[5] <- c(rep(0, each=30))
data2[6] <- c(rep(10, each=30))

#create list with names of datasets
names <- c('data1','data2')

#function for sorting
examplefunction <- function(VarNames) {
  for (i in 1:length(VarNames)) {
    #get current dataset
    name <- VarNames[i]
    data <- get(VarNames[i])

    #create new empty data.frames for sorting
    data.0 <- data.frame(matrix(nrow=30))
    name.data.0 <- paste(name,"0", sep=".")
    c.0 = 2 #start at second column, since first doesn't like the colname later
    data.1 <- data.frame(matrix(nrow=30))
    name.data.1 <- paste(name,"1", sep=".")
    c.1 = 2
    data.5 <- data.frame(matrix(nrow=30))
    name.data.5 <- paste(name,"5", sep=".")
    c.5 = 2
    data.10 <- data.frame(matrix(nrow=30))
    name.data.10 <- paste(name,"10", sep=".")
    c.10 = 2

    #sort data into new different data.frames
    for (c in 1:ncol(data)) {

      if(data[1,c]==0) {
        data.0[c.0] = data[c]
        c.0 = c.0 +1
      }
      else if(data[1,c]==1) {
        data.1[c.1] = data[c]
        c.1 = c.1 +1
      }
      else if(data[1,c]==5) {
        data.5[c.5] = data[c]
        c.5 = c.5 +1
      }
      else if(data[1,c]==10) {
        data.10[c.10] = data[c]
        c.10 = c.10 +1
      }
      else (stop="new values")
    }

    #remove first column with weird name
    data.0 <- data.0[,-1] 
    data.1 <- data.1[,-1] 
    data.5 <- data.5[,-1] 
    data.10 <- data.10[,-1] 

    #assign data frames to global environment
    assign(name.data.0, data.0, envir = .GlobalEnv)
    assign(name.data.1, data.1, envir = .GlobalEnv)
    assign(name.data.5, data.5, envir = .GlobalEnv)
    assign(name.data.10, data.10, envir = .GlobalEnv)

  }
}

#function call
examplefunction(names)

如前所述,如果您 运行 这样做,您最终将得到 0 个变量和 >1 个变量的数据帧。 三个向量,其中数据框只有一列。

所以我的问题是: 1. 有没有办法保持数据类型并强制 R 将其分配给数据框而不是向量? 2. 或者有没有我可以使用的替代函数来代替 assign()?如果我使用 <<- 我怎样才能像上面那样分配名称?

子集化时可以使用drop = FALSE:

examplefunction <- function(VarNames) {
    for (i in 1:length(VarNames)) {
        #get current dataset
        name <- VarNames[i]
        data <- get(VarNames[i])

        #create new empty data.frames for sorting
        data.0 <- data.frame(matrix(nrow=30))
        name.data.0 <- paste(name,"0", sep=".")
        c.0 = 2 #start at second column, since first doesn't like the colname later
        data.1 <- data.frame(matrix(nrow=30))
        name.data.1 <- paste(name,"1", sep=".")
        c.1 = 2
        data.5 <- data.frame(matrix(nrow=30))
        name.data.5 <- paste(name,"5", sep=".")
        c.5 = 2
        data.10 <- data.frame(matrix(nrow=30))
        name.data.10 <- paste(name,"10", sep=".")
        c.10 = 2

        #sort data into new different data.frames
        for (c in 1:ncol(data)) {

            if(data[1,c]==0) {
                data.0[c.0] = data[c]
                c.0 = c.0 +1
            }
            else if(data[1,c]==1) {
                data.1[c.1] = data[c]
                c.1 = c.1 +1
            }
            else if(data[1,c]==5) {
                data.5[c.5] = data[c]
                c.5 = c.5 +1
            }
            else if(data[1,c]==10) {
                data.10[c.10] = data[c]
                c.10 = c.10 +1
            }
            else (stop="new values")
        }

        #remove first column with weird name
        data.0  <- data.0[ , -1, drop = FALSE]
        data.1  <- data.1[ , -1, drop = FALSE]
        data.5  <- data.5[ , -1, drop = FALSE]
        data.10 <- data.10[ , -1, drop = FALSE] 

        #assign data frames to global environment
        assign(name.data.0,  data.0,  envir = .GlobalEnv)
        assign(name.data.1,  data.1,  envir = .GlobalEnv)
        assign(name.data.5,  data.5,  envir = .GlobalEnv)
        assign(name.data.10, data.10, envir = .GlobalEnv)

    }
}

#function call
examplefunction(names)

让我们看一下单列数据帧:

str(data1.1)
'data.frame':   30 obs. of  1 variable:
  $ X1: num  1 1 1 1 1 1 1 1 1 1 ...
str(data2.10)
'data.frame':   30 obs. of  1 variable:
  $ X6: num  10 10 10 10 10 10 10 10 10 10 ...

现在,综上所述,我同意 Roland 的评论——您几乎不想采用这种以复杂方式分配给全局环境的方法,而应该 return 一个列表;这是最佳实践。但是,您仍然需要 drop = FALSE 来保留列名。 真的,对我来说,可能有一种 完全不同的 方法来做你想做的任何类型的数据争论,这是一种更好的方法。我只是没有很好地掌握你的任务来提出建议。