【问题标题】:Add (insert) a column between two columns in a data.frame在 data.frame 的两列之间添加(插入)一列
【发布时间】:2012-11-10 06:07:53
【问题描述】:

我有一个包含 a、b 和 c 列的数据框。我想在 b 和 c 之间添加一个新的 d 列。

我知道我可以使用 cbind 在末尾添加 d,但是如何在两列之间插入它?

【问题讨论】:

  • 也许这就是你想要的:r.789695.n4.nabble.com/…
  • dplyr 包中的 mutate() 函数是否允许按此问题所述添加列?

标签: r dataframe insert


【解决方案1】:

我会简单地使用cbind()

> df <- data.frame(a=1:5,
+                  b=10:14,
+                  c=rep(0,5),
+                  d=7:11)
> 
> z <- LETTERS[1:5]
> df <- cbind(df[,1:2], z, df[,3:4]) # Puts the z column between 2nd and 3rd column of df
> df
  a  b z c  d
1 1 10 A 0  7
2 2 11 B 0  8
3 3 12 C 0  9
4 4 13 D 0 10
5 5 14 E 0 11

【讨论】:

    【解决方案2】:

    如果您不能假设列 b 出现在 c 之前,您可以使用 match 查找两者的列号,min 获取较低的列号,seq_len 获取序列,直到本栏目。然后您可以先将此索引用作 positive 子集,然后放置新列 d,然后再次将该序列用作 negative 子集。

    i <- seq_len(min(match(c("b", "c"), colnames(x))))
    data.frame(x[i], d, x[-i])
    #cbind(x[i], d, x[-i]) #Alternative
    #  a b  d c
    #1 1 4 10 7
    #2 2 5 11 8
    #3 3 6 12 9
    

    如果您知道b 列在c 之前,您可以将新列d 放在b 之后:

    i <- seq_len(match("b", colnames(x)))
    data.frame(x[i], d, x[-i])
    #  a b  d c
    #1 1 4 10 7
    #2 2 5 11 8
    #3 3 6 12 9
    

    数据:

    x <- data.frame(a = 1:3, b = 4:6, c = 7:9)
    d <- 10:12
    

    【讨论】:

      【解决方案3】:
      df <- data.frame(a=c(1,2), b=c(3,4), c=c(5,6))
      df %>%
        mutate(d= a/2) %>%
        select(a, b, d, c)
      

      结果

        a b   d c
      1 1 3 0.5 5
      2 2 4 1.0 6
      

      我建议在dplyr::mutate 之后使用dplyr::select。它有许多帮助器来选择/取消选择列的子集。

      在此问题的上下文中,您选择的顺序将反映在输出 data.frame 中。

      【讨论】:

        【解决方案4】:

        您可以使用append() 函数将项目插入向量或列表(数据框是列表)。简单地说:

        df <- data.frame(a=c(1,2), b=c(3,4), c=c(5,6))
        
        df <- as.data.frame(append(df, list(d=df$b+df$c), after=2))
        

        或者,如果您想通过名称指定位置,请使用which

        df <- as.data.frame(append(df, list(d=df$b+df$c), after=which(names(df)=="b")))
        

        【讨论】:

          【解决方案5】:

          添加到您的新列中:

          df$d <- list/data
          

          然后你可以重新排序。

          df <- df[, c("a", "b", "d", "c")]
          

          【讨论】:

          • 我发现使用setcolorder 和列号(而不是它们的名称)重新排序也非常有用,因为一旦列数变得非常大,您就可以开始使用seqrep完成大部分工作。可以使用加算术运算符。例如。 setcolorder(data, c(1, (num_cols -2), (num_cols -1), num_cols, seq(from = 2, to = (num_cols - 3))))
          • 我应该提一下,setcolorder 用于 data.table,而不是 data.frame!
          【解决方案6】:

          简单的解决方案。在具有 5 列的数据框中,如果要在 3 到 4 之间插入另一列...

          tmp <- data[, 1:3]
          tmp$example <- NA # or any value.
          data <- cbind(tmp, data[, 4:5]
          

          【讨论】:

            【解决方案7】:

            你可以像下面那样做 -

            df <- data.frame(a=1:4, b=5:8, c=9:12)
            df['d'] <- seq(10,13)
            df <- df[,c('a','b','d','c')]
            

            【讨论】:

              【解决方案8】:

              这是一个如何将列从最后一个位置移动到第一个位置的示例。它结合了[ncol。我认为在这里为忙碌的读者提供一个非常简短的答案会很有用:

              d = mtcars
              d[, c(ncol(d), 1:(ncol(d)-1))] 
              

              【讨论】:

                【解决方案9】:

                我建议你使用 tibble 包中的函数 add_column()

                library(tibble)
                dataset <- data.frame(a = 1:5, b = 2:6, c=3:7)
                add_column(dataset, d = 4:8, .after = 2)
                

                请注意,您可以使用列名代替列索引:

                add_column(dataset, d = 4:8, .after = "b")
                

                如果更方便的话,或者使用参数.before 而不是.after

                add_column(dataset, d = 4:8, .before = "c")
                

                【讨论】:

                • 我删除了名称删除。似乎没有增加多少,虽然 Hadley 被列为 an 包的作者,但 Kirill Müller 被列为 creator and maintainer
                【解决方案10】:

                创建一个示例 data.frame 并向其中添加一列。

                df = data.frame(a = seq(1, 3), b = seq(4,6), c = seq(7,9))
                df['d'] <- seq(10,12)
                df
                
                  a b c  d
                1 1 4 7 10
                2 2 5 8 11
                3 3 6 9 12
                

                按列索引重新排列

                df[, colnames(df)[c(1:2,4,3)]]
                

                或按列名

                df[, c('a', 'b', 'd', 'c')]
                

                结果是

                  a b  d c
                1 1 4 10 7
                2 2 5 11 8
                3 3 6 12 9
                

                【讨论】:

                  【解决方案11】:

                  R 没有指定添加新列的位置的功能。例如,mtcars$mycol&lt;-'foo'。它总是作为最后一列添加。使用其他方式(例如,dplyr's select())您可以将 mycol 移动到所需位置。这并不理想,R 可能希望在未来尝试改变它。

                  【讨论】:

                  • 是的,它有append功能。
                  【解决方案12】:

                  假设c 总是紧跟在b 之后,无论b 在您的data.frame 中的哪个位置,此代码都会在b 之后添加一列。

                  > test <- data.frame(a=1,b=1,c=1)
                  > test
                    a b c
                  1 1 1 1
                  
                  > bspot <- which(names(test)=="b")
                  
                  > data.frame(test[1:bspot],d=2,test[(bspot+1):ncol(test)])
                    a b d c
                  1 1 1 2 1
                  

                  或者可能更自然:

                  data.frame(append(test, list(d=2), after=match("b", names(test))))
                  

                  【讨论】:

                    【解决方案13】:

                    此函数在数据框中的所有预先存在的列之间插入一个零列。

                    insertaCols<-function(dad){   
                      nueva<-as.data.frame(matrix(rep(0,nrow(daf)*ncol(daf)*2 ),ncol=ncol(daf)*2))  
                       for(k in 1:ncol(daf)){   
                          nueva[,(k*2)-1]=daf[,k]   
                          colnames(nueva)[(k*2)-1]=colnames(daf)[k]  
                          }  
                       return(nueva)   
                      }
                    

                    【讨论】:

                      【解决方案14】:

                      为了它的价值,我写了一个函数来做到这一点:

                      [已删除]


                      我现在用beforeafter 功能更新了这个函数,并将place 默认为1。它还具有数据表兼容性:

                      #####
                      # FUNCTION: InsertDFCol(colName, colData, data, place = 1, before, after)
                      # DESCRIPTION: Takes in a data, a vector of data, a name for that vector and a place to insert this vector into
                      # the data frame as a new column. If you put place = 3, the new column will be in the 3rd position and push the current
                      # 3rd column up one (and each subsuquent column up one). All arguments must be set. Adding a before and after
                      # argument that will allow the user to say where to add the new column, before or after a particular column.
                      # Please note that if before or after is input, it WILL override the place argument if place is given as well. Also, place
                      # defaults to adding the new column to the front.
                      #####
                      
                      InsertDFCol <- function(colName, colData, data, place = 1, before, after) {
                      
                        # A check on the place argument.
                        if (length(names(data)) < place) stop("The place argument exceeds the number of columns in the data for the InsertDFCol function. Please check your place number")
                        if (place <= 0 & (!missing(before) | !(missing(after)))) stop("You cannot put a column into the 0th or less than 0th position. Check your place argument.")
                        if (place %% 1 != 0 & (!missing(before) | !(missing(after)))) stop("Your place value was not an integer.")
                        if (!(missing(before)) & !missing(after)) stop("You cannot designate a before AND an after argument in the same function call. Please use only one or the other.")
                      
                        # Data Table compatability.
                        dClass <- class(data)
                        data <- as.data.frame(data)
                      
                        # Creating booleans to define whether before or after is given.
                        useBefore <- !missing(before)
                        useAfter <- !missing(after)
                      
                        # If either of these are true, then we are using the before or after argument, run the following code.
                        if (useBefore | useAfter) {
                      
                          # Checking the before/after argument if given. Also adding regular expressions.
                          if (useBefore) { CheckChoice(before, names(data)) ; before <- paste0("^", before, "$") }
                          if (useAfter) { CheckChoice(after, names(data)) ; after <- paste0("^", after, "$") }
                      
                          # If before or after is given, replace "place" with the appropriate number.
                          if (useBefore) { newPlace <- grep(before, names(data)) ; if (length(newPlace) > 1) { stop("Your before argument matched with more than one column name. Do you have duplicate column names?!") }}
                          if (useAfter) { newPlace <- grep(after, names(data)) ; if (length(newPlace) > 1) { stop("Your after argument matched with more than one column name. Do you have duplicate column names?!") }}
                          if (useBefore) place <- newPlace # Overriding place.
                          if (useAfter) place <- newPlace + 1 # Overriding place.
                      
                        }
                      
                        # Making the new column.
                        data[, colName] <- colData
                      
                        # Finding out how to reorder this.
                        # The if statement handles the case where place = 1.
                        currentPlace <- length(names(data)) # Getting the place of our data (which should have been just added at the end).
                        if (place == 1) {
                      
                          colOrder <- c(currentPlace, 1:(currentPlace - 1))
                      
                        } else if (place == currentPlace) { # If the place to add the new data was just at the end of the data. Which is stupid...but we'll add support anyway.
                      
                          colOrder <- 1:currentPlace
                      
                        } else { # Every other case.
                      
                          firstHalf <- 1:(place - 1) # Finding the first half on columns that come before the insertion.
                          secondHalf <- place:(currentPlace - 1) # Getting the second half, which comes after the insertion.
                          colOrder <- c(firstHalf, currentPlace, secondHalf) # Putting that order together.
                      
                        }
                      
                        # Reordering the data.
                        data <- subset(data, select = colOrder)
                      
                        # Data Table compatability.
                        if (dClass[1] == "data.table") data <- as.data.table(data)
                      
                        # Returning.
                        return(data)
                      
                      }
                      

                      我意识到我也没有包括 CheckChoice:

                      #####
                      # FUNCTION: CheckChoice(names, dataNames, firstWord == "Oops" message = TRUE)                                                                                               
                      # DESCRIPTION: Takes the column names of a data frame and checks to make sure whatever "choice" you made (be it 
                      # your choice of dummies or your choice of chops) is actually in the data frame columns. Makes troubleshooting easier. 
                      # This function is also important in prechecking names to make sure the formula ends up being right. Use it after 
                      # adding in new data to check the "choose" options. Set firstWord to the first word you want said before an exclamation point.
                      # The warn argument (previously message) can be set to TRUE if you only want to 
                      #####
                      
                      CheckChoice <- function(names, dataNames, firstWord = "Oops", warn = FALSE) {
                      
                        for (name in names) {
                      
                          if (warn == TRUE) { if(!(name %in% dataNames)) { warning(paste0(firstWord, "! The column/value/argument, ", name, ", was not valid OR not in your data! Check your input! This is a warning message of that!")) } }
                          if (warn == FALSE) { if(!(name %in% dataNames)) { stop(paste0(firstWord, "! The column/value/argument, " , name, ", was not valid OR not in your data! Check your input!")) } }
                      
                        }
                      }
                      

                      【讨论】:

                        【解决方案15】:

                        这是一种在数据框的特定位置插入列的快速而肮脏的方法。就我而言,我在原始数据框中有 5 列:c1, c2, c3, c4, c5,我将在 c2c3 之间插入一个新列 c2b

                        1) 我们先创建测试数据框:

                        > dataset <- data.frame(c1 = 1:5, c2 = 2:6, c3=3:7, c4=4:8, c5=5:9)
                        > dataset
                          c1 c2 c3 c4 c5
                        1  1  2  3  4  5
                        2  2  3  4  5  6
                        3  3  4  5  6  7
                        4  4  5  6  7  8
                        5  5  6  7  8  9
                        

                        2) 在我们的数据框末尾添加新列c2b

                        > dataset$c2b <- 10:14
                        > dataset
                          c1 c2 c3 c4 c5 c2b
                        1  1  2  3  4  5  10
                        2  2  3  4  5  6  11
                        3  3  4  5  6  7  12
                        4  4  5  6  7  8  13
                        5  5  6  7  8  9  14
                        

                        3) 根据列索引对数据框重新排序。在我的例子中,我想在现有的第 2 列和第 3 列之间插入新的列 (6)。我通过使用向量 c(1:2, 6, 3:5)(相当于 c(1, 2, 6, 3, 4, 5))来寻址我的数据框中的列来做到这一点。

                        > dataset <- dataset[,c(1:2, 6, 3:5)]
                        > dataset
                          c1 c2 c2b c3 c4 c5
                        1  1  2  10  3  4  5
                        2  2  3  11  4  5  6
                        3  3  4  12  5  6  7
                        4  4  5  13  6  7  8
                        5  5  6  14  7  8  9
                        

                        那里!

                        【讨论】:

                          【解决方案16】:

                          `

                          data1 <- data.frame(col1=1:4, col2=5:8, col3=9:12)
                          row.names(data1) <- c("row1","row2","row3","row4")
                          data1
                          data2 <- data.frame(col1=21:24, col2=25:28, col3=29:32)
                          row.names(data2) <- c("row1","row2","row3","row4")
                          data2
                          insertPosition = 2
                          leftBlock <- unlist(data1[,1:(insertPosition-1)])
                          insertBlock <- unlist(data2[,1:length(data2[1,])])
                          rightBlock <- unlist(data1[,insertPosition:length(data1[1,])])
                          newData <- matrix(c(leftBlock, insertBlock, rightBlock), nrow=length(data1[,1]), byrow=FALSE)
                          newData
                          

                          `

                          【讨论】:

                            【解决方案17】:

                            您想将 z 列添加到旧数据框 (old.df) 由 x 和 y 列定义。

                            z = rbinom(1000, 5, 0.25)
                            old.df <- data.frame(x = c(1:1000), y = rnorm(1:1000))
                            head(old.df)
                            

                            定义一个名为 new.df 的新数据框

                            new.df <- data.frame(x = old.df[,1], z, y = old.df[,2])
                            head(new.df)
                            

                            【讨论】:

                              【解决方案18】:

                              您可以使用 [ 重新排序列,或按您想要的顺序显示列。

                              d <- data.frame(a=1:4, b=5:8, c=9:12)
                              target <- which(names(d) == 'b')[1]
                              cbind(d[,1:target,drop=F], data.frame(d=12:15), d[,(target+1):length(d),drop=F])
                              
                                a b  d  c
                              1 1 5 12  9
                              2 2 6 13 10
                              3 3 7 14 11
                              4 4 8 15 12
                              

                              【讨论】:

                              • 这是一个很好的答案。但我不得不承认,这也是 R 语言对初学者来说很难的一个很好的例子。
                              • 话虽如此,我认为@ashah57 下面有一个更简单、更清晰的答案。没必要对这样的事情太花哨。
                              猜你喜欢
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2011-07-16
                              • 2017-10-29
                              • 2023-03-10
                              • 2016-09-27
                              • 2015-07-22
                              相关资源
                              最近更新 更多