Add (insert) a column between two columns in a data.frame

前端 未结 17 1490
耶瑟儿~
耶瑟儿~ 2020-11-28 02:41

I have a data frame that has columns a, b, and c. I\'d like to add a new column d between b and c.

I know I could just add d at the end by using cbind but h

相关标签:
17条回答
  • 2020-11-28 03:12

    Create an example data.frame and add a column to it.

    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
    

    Rearrange by column index

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

    or by column name

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

    The result is

      a b  d c
    1 1 4 10 7
    2 2 5 11 8
    3 3 6 12 9
    
    0 讨论(0)
  • 2020-11-28 03:12
    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)
    

    results

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

    I suggest to use dplyr::select after dplyr::mutate. It has many helpers to select/de-select subset of columns.

    In the context of this question the order by which you select will be reflected in the output data.frame.

    0 讨论(0)
  • 2020-11-28 03:13

    Easy solution. In a data frame with 5 columns, If you want insert another column between 3 and 4...

    tmp <- data[, 1:3]
    tmp$example <- NA # or any value.
    data <- cbind(tmp, data[, 4:5]
    
    0 讨论(0)
  • 2020-11-28 03:14

    Add in your new column:

    df$d <- list/data
    

    Then you can reorder them.

    df <- df[, c("a", "b", "d", "c")]
    
    0 讨论(0)
  • 2020-11-28 03:17

    For what it's worth, I wrote a function to do this:

    [removed]


    I have now updated this function with before and after functionality and defaulting place to 1. It also has data table compatability:

    #####
    # 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)
    
    }
    

    I realized I also did not include 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!")) } }
    
      }
    }
    
    0 讨论(0)
  • 2020-11-28 03:17

    You can do it like below -

    df <- data.frame(a=1:4, b=5:8, c=9:12)
    df['d'] <- seq(10,13)
    df <- df[,c('a','b','d','c')]
    
    0 讨论(0)
提交回复
热议问题