Dodaj (wstaw) kolumnę między dwiema kolumnami w data.frame

89

Mam ramkę danych zawierającą kolumny a, b i c. Chciałbym dodać nową kolumnę d między b i c.

Wiem, że mógłbym po prostu dodać d na końcu, używając cbind, ale jak mogę wstawić go między dwie kolumny?

znak
źródło
Może to robi to, co chcesz: r.789695.n4.nabble.com/…
Mark Miller
1
czy funkcja mutate () w pakiecie dplyr pozwala na dodawanie kolumn, jak podano w tym pytaniu?
marbel

Odpowiedzi:

83

Proponuję skorzystać z funkcji add_column()z tibblepakietu.

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

Zauważ, że możesz użyć nazw kolumn zamiast indeksu kolumn:

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

Lub użyj argumentu .beforezamiast, .afterjeśli wygodniej.

add_column(dataset, d = 4:8, .before = "c")
Kevin Zarca
źródło
6
Usunąłem zrzucanie nazw. Nie wydaje się, aby dodać dużo, a podczas Hadley jest wymieniony jako na autora pakietu Kirill Müller jest wymieniony jako twórcy i opiekuna .
Gregor Thomas
39

Dodaj w nowej kolumnie:

df$d <- list/data

Następnie możesz je ponownie zamówić.

df <- df[, c("a", "b", "d", "c")]
ashah57
źródło
1
Uważam, że zmiana kolejności używania setcolorderw połączeniu z numerami kolumn (w przeciwieństwie do ich nazw) również jest bardzo przydatna, ponieważ gdy liczba kolumn stanie się bardzo duża, możesz zacząć używać seqi repwykonywać większość pracy. Można również stosować operatory arytmetyczne. Np.setcolorder(data, c(1, (num_cols -2), (num_cols -1), num_cols, seq(from = 2, to = (num_cols - 3))))
n1k31t4
1
Powinienem wspomnieć, że setcolorderjest przeznaczony dla tabeli danych, a nie ramki danych!
n1k31t4
21

Możesz zmienić kolejność kolumn za pomocą [lub przedstawić kolumny w żądanej kolejności.

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
Matthew Lundberg
źródło
13
To świetna odpowiedź. Ale muszę przyznać, że jest to również świetny przykład tego, dlaczego R może być trudny dla początkujących.
tumultous_rooster
2
Biorąc to pod uwagę, myślę, że @ ashah57 ma znacznie prostszą i czystszą odpowiedź poniżej. Nie ma potrzeby, aby coś takiego wyglądało jak to.
tumultous_rooster
12

Zakładając, że czawsze następuje bto natychmiast , ten kod doda kolumnę po każdym bmiejscu bw data.frame.

> 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

Lub bardziej naturalnie:

data.frame(append(test, list(d=2), after=match("b", names(test))))
thelatemail
źródło
5

Utwórz przykładową ramkę data.frame i dodaj do niej kolumnę.

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

Zmień kolejność według indeksu kolumn

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

lub według nazwy kolumny

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

Wynik to

  a b  d c
1 1 4 10 7
2 2 5 11 8
3 3 6 12 9
buhtz
źródło
3

Chciałbyś dodać kolumnę z do starej ramki danych (stary.df) zdefiniowanej przez kolumny x i y.

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

Zdefiniuj nową ramkę danych o nazwie new.df

new.df <- data.frame(x = old.df[,1], z, y = old.df[,2])
head(new.df)
marbel
źródło
3

Oto szybki i brudny sposób wstawiania kolumny w określonej pozycji w ramce danych. W moim przypadku mam 5 kolumn w oryginalnej ramce danych: c1, c2, c3, c4, c5i wstawię nową kolumnę c2bmiędzy c2a c3.

1) Najpierw utwórzmy ramkę danych testowych:

> 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) Dodaj nową kolumnę c2bna końcu naszej ramki danych:

> 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) Zmień kolejność ramki danych na podstawie indeksów kolumn. W moim przypadku chcę wstawić nową kolumnę (6) między istniejące kolumny 2 i 3. Robię to, adresując kolumny w mojej ramce danych za pomocą wektora, c(1:2, 6, 3:5)który jest równoważny 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

Tam!

Ricardo
źródło
2

Na co warto napisałem funkcję, aby to zrobić:

[oddalony]


Mam teraz zaktualizowane z tej funkcji beforei afterfunkcjonalność i zalegających placena 1. Posiada również tabeli danych kompatybilność:

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

}

Zdałem sobie sprawę, że nie uwzględniłem też 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!")) } }

  }
}
żyrafa
źródło
2

Proste rozwiązanie. W ramce danych z 5 kolumnami, jeśli chcesz wstawić kolejną kolumnę między 3 a 4 ...

tmp <- data[, 1:3]
tmp$example <- NA # or any value.
data <- cbind(tmp, data[, 4:5]
Jose Luis Camps
źródło
1

Ta funkcja wstawia jedną kolumnę zerową między wszystkie wcześniej istniejące kolumny w ramce danych.

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)   
  }
Gabriel Tadeo del Campo
źródło
1

Oto przykład, jak przenieść kolumnę z ostatniej na pierwszą pozycję. Łączy się [z ncol. Pomyślałem, że przydałaby się tutaj bardzo krótka odpowiedź dla zajętego czytelnika:

d = mtcars
d[, c(ncol(d), 1:(ncol(d)-1))] 
Patrick T.
źródło
1

Możesz użyć tej append()funkcji, aby wstawić elementy do wektorów lub list (ramki danych to listy). Po prostu:

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

Lub, jeśli chcesz określić pozycję według nazwy, użyj which:

df <- as.data.frame(append(df, list(d=df$b+df$c), after=which(names(df)=="b")))
Simon Woodward
źródło
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

`

Iordanov K.
źródło
0

R nie ma funkcji określania miejsca dodawania nowej kolumny. Np mtcars$mycol<-'foo'. Zawsze jest dodawany jako ostatnia kolumna. Używając innych środków (np. dplyr's select()) Możesz przesunąć mykol do żądanej pozycji. To nie jest idealne rozwiązanie i R może chcieć to zmienić w przyszłości.

userJT
źródło
Tak, ma appendfunkcję.
Simon Woodward
0

Możesz to zrobić jak poniżej -

df <- data.frame(a=1:4, b=5:8, c=9:12)
df['d'] <- seq(10,13)
df <- df[,c('a','b','d','c')]
Tanvir ahmad
źródło
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)

wyniki

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

Proponuję użyć dplyr::selectpo dplyr::mutate. Ma wielu pomocników do zaznaczania / usuwania zaznaczenia podzbioru kolumn.

W kontekście tego pytania kolejność wyboru zostanie odzwierciedlona w wyjściowej ramce data.frame.

Kresten
źródło
0

Kiedy nie możesz założyć, że kolumna bwystępuje wcześniej c, możesz użyć matchdo znalezienia numeru kolumny obu, minaby uzyskać niższy numer kolumny i seq_lenuzyskać sekwencję do tej kolumny. Następnie możesz najpierw użyć tego indeksu jako podzbioru dodatniego , następnie umieścić nową kolumnę, da następnie użyć sekwencji ponownie jako podzbioru ujemnego .

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

W przypadku, gdy wiesz, że kolumna bpojawi się przed cumieszczeniem nowej kolumny dpo 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

Dane:

x <- data.frame(a = 1:3, b = 4:6, c = 7:9)
d <- 10:12
GKi
źródło