Thêm (chèn) một cột giữa hai cột trong data.frame


87

Tôi có một khung dữ liệu có các cột a, b và c. Tôi muốn thêm một cột d mới giữa b và c.

Tôi biết tôi chỉ có thể thêm d vào cuối bằng cách sử dụng cbind nhưng làm thế nào tôi có thể chèn nó vào giữa hai cột?


Có lẽ điều này làm những gì bạn muốn: r.789695.n4.nabble.com/...
Mark Miller

1
Hàm mutate () trong gói dplyr có cho phép thêm các cột như đã nêu trong câu hỏi này không?
marbel

Câu trả lời:


81

Tôi sẽ đề nghị bạn sử dụng chức năng add_column()từ tibblegói.

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

Lưu ý rằng bạn có thể sử dụng tên cột thay vì chỉ mục cột:

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

Hoặc sử dụng đối số .beforethay vì .afternếu thuận tiện hơn.

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

6
Tôi đã xóa bỏ tên. Dường như không để thêm nhiều, và trong khi Hadley được liệt kê như là một tác giả của gói Kirill Müller được liệt kê như người sáng tạo và duy trì .
Gregor Thomas

38

Thêm vào cột mới của bạn:

df$d <- list/data

Sau đó, bạn có thể sắp xếp lại chúng.

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

1
Tôi thấy việc sắp xếp lại thứ tự bằng cách sử dụng setcolorderkết hợp với số cột (trái ngược với tên của chúng) cũng rất hữu ích, bởi vì một khi số lượng cột trở nên rất lớn, bạn có thể bắt đầu sử dụng seqrepthực hiện hầu hết công việc. Các toán tử số học cộng có thể được sử dụng. Vdsetcolorder(data, c(1, (num_cols -2), (num_cols -1), num_cols, seq(from = 2, to = (num_cols - 3))))
n1k31t4

1
Tôi nên đề cập, setcolorderđược dành cho data.table, không phải data.frame!
n1k31t4

21

Bạn có thể sắp xếp lại các cột với [hoặc trình bày các cột theo thứ tự bạn muốn.

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

13
Đây là một câu trả lời tuyệt vời. Nhưng tôi phải thừa nhận rằng, đây cũng là một ví dụ tuyệt vời về lý do tại sao R có thể gây khó khăn cho người mới bắt đầu.
tumultous_rooster

2
Nói như vậy, tôi nghĩ @ ashah57 có một câu trả lời đơn giản và rõ ràng hơn nhiều bên dưới. Không cần phải quá ưa thích những thứ như thế này.
tumultous_rooster

12

Giả sử cluôn luôn theo sau b, mã này sẽ thêm một cột sau bbất kể vị trí nào btrong data.frame của bạn.

> 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

Hoặc có thể tự nhiên hơn:

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

5

Tạo một data.frame mẫu và thêm một cột vào đó.

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

Sắp xếp lại theo chỉ mục cột

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

hoặc theo tên cột

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

Kết quả là

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

3

Bạn muốn thêm cột z vào khung dữ liệu cũ (old.df) được xác định bởi các cột x và y.

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

Xác định khung dữ liệu mới có tên new.df

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

2

Đây là một cách nhanh chóng và dễ dàng để chèn một cột vào một vị trí cụ thể trên khung dữ liệu. Trong trường hợp của tôi, tôi có 5 cột trong khung dữ liệu ban đầu: c1, c2, c3, c4, c5và tôi sẽ chèn một cột mới c2bgiữa c2c3.

1) Đầu tiên hãy tạo khung dữ liệu thử nghiệm:

> 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) Thêm cột mới c2bvào cuối khung dữ liệu của chúng tôi:

> 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) Sắp xếp lại khung dữ liệu dựa trên các chỉ mục cột. Trong trường hợp của tôi, tôi muốn chèn cột mới (6) vào giữa các cột hiện có 2 và 3. Tôi làm điều đó bằng cách định địa chỉ các cột trên khung dữ liệu của tôi bằng cách sử dụng vectơ c(1:2, 6, 3:5)tương đương với 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

Đây!


2

Đối với những gì nó đáng giá, tôi đã viết một hàm để làm điều này:

[đã loại bỏ]


Bây giờ tôi đã cập nhật chức năng này với beforeafterchức năng và mặc định placelà 1. Nó cũng có khả năng tương thích bảng dữ liệu:

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

}

Tôi nhận ra rằng tôi cũng không bao gồm 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!")) } }

  }
}

2

Giải pháp dễ dàng. Trong khung dữ liệu có 5 cột, Nếu bạn muốn chèn một cột khác từ 3 đến 4 ...

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

1

Hàm này chèn một cột 0 giữa tất cả các cột tồn tại trước đó trong khung dữ liệu.

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

1

Đây là một ví dụ về cách di chuyển một cột từ vị trí cuối cùng sang vị trí đầu tiên. Nó kết hợp [với ncol. Tôi nghĩ sẽ hữu ích nếu có một câu trả lời rất ngắn gọn ở đây cho những người đọc bận rộn:

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

1

Bạn có thể sử dụng append()chức năng để chèn các mục vào vectơ hoặc danh sách (khung dữ liệu là danh sách). Đơn giản:

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

Hoặc, nếu bạn muốn chỉ định vị trí theo tên, hãy sử dụng which:

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

0

`

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

`


0

R không có chức năng chỉ định vị trí cột mới được thêm vào. Ví dụ mtcars$mycol<-'foo'. Nó luôn được thêm vào cột cuối cùng. Sử dụng các phương tiện khác (ví dụ dplyr's select():) bạn có thể di chuyển mycol đến vị trí mong muốn. Điều này không lý tưởng và R có thể muốn cố gắng thay đổi điều đó trong tương lai.


Vâng, nó có appendchức năng.
Simon Woodward

0

Bạn có thể làm như dưới đây -

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

các kết quả

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

Tôi đề nghị sử dụng dplyr::selectsau khi dplyr::mutate. Nó có nhiều trợ giúp để chọn / bỏ chọn tập hợp con của các cột.

Trong ngữ cảnh của câu hỏi này, thứ tự mà bạn chọn sẽ được phản ánh trong khung dữ liệu đầu ra.


0

Khi bạn không thể giả định rằng cột đó bxuất hiện trước khi cbạn có thể sử dụng matchđể tìm số cột của cả hai, minđể lấy số cột dưới và seq_lenđể có một chuỗi cho đến cột này. Sau đó, bạn có thể sử dụng chỉ mục này trước tiên như một tập hợp con dương , thay vì đặt cột mới dvà sau đó sử dụng lại chuỗi dưới dạng tập hợp con âm .

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

Trong trường hợp bạn biết cột đó bxuất hiện trước khi cbạn có thể đặt cột mới dsau 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

Dữ liệu:

x <- data.frame(a = 1:3, b = 4:6, c = 7:9)
d <- 10:12
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.