Benennen Sie mehrere Spalten nach Namen um


84

Jemand hätte das schon fragen sollen, aber ich konnte keine Antwort finden. Sagen wir, ich habe:

x = data.frame(q=1,w=2,e=3, ...and many many columns...)  

Was ist der eleganteste Weg, um eine beliebige Teilmenge von Spalten, deren Position ich nicht unbedingt kenne, in andere beliebige Namen umzubenennen?

Beispiel: Ich möchte umbenennen "q"und "e"in "A"und "B", was ist der eleganteste Code, um dies zu tun?

Natürlich kann ich eine Schleife machen:

oldnames = c("q","e")
newnames = c("A","B")
for(i in 1:2) names(x)[names(x) == oldnames[i]] = newnames[i]

Aber ich frage mich, ob es einen besseren Weg gibt? Vielleicht mit einigen der Pakete? ( plyr::renameetc.)

Antworten:


106

setnamesaus dem data.tablePaket funktioniert auf data.frames oder data.tables

library(data.table)
d <- data.frame(a=1:2,b=2:3,d=4:5)
setnames(d, old = c('a','d'), new = c('anew','dnew'))
d


 #   anew b dnew
 # 1    1 2    4
 # 2    2 3    5

Beachten Sie, dass Änderungen durch Verweis vorgenommen werden, also kein Kopieren (auch für data.frames!)


1
Für verspätete Ankünfte hier - Schauen Sie sich auch Joels Antwort an, die das Überprüfen auf vorhandene Spalten abdeckt, falls Sie eine Liste von Namensänderungen haben, die möglicherweise nicht alle vorhanden sind, z. B.old = c("a", "d", "e")
micstr

1
Ich frage mich, ob dies funktioniert, wenn Sie nur eine Teilmenge / einige der Spalten anstelle aller umbenennen möchten. Wenn ich also einen Datenrahmen mit zehn Spalten hatte und _id_firstname in firstname und _id_lastname in lastname umbenennen wollte, aber die verbleibenden acht Spalten unberührt ließen, kann ich dies tun oder muss ich alle Spalten auflisten?
Mus

@MusTheDataGuy Sie geben die Teilmenge der neuen und alten Namen an, und es wird funktionieren.
mnel

@mnel Ich muss die Variablennamen einer Teilmenge ändern, wenn @Mus gefragt wird. Der obige Code funktionierte jedoch nicht für eine Teilmenge von Daten. @ Gorkas Antwort mit rename_at()arbeitete daran, Variablennamen einer Teilmenge zu ändern.
Mehmet Yildirim

95

Mit dplyr würden Sie tun:

library(dplyr)

df = data.frame(q = 1, w = 2, e = 3)
    
df %>% rename(A = q, B = e)

#  A w B
#1 1 2 3

Oder wenn Sie Vektoren verwenden möchten, wie von @ Jelena-bioinf vorgeschlagen:

library(dplyr)

df = data.frame(q = 1, w = 2, e = 3)

oldnames = c("q","e")
newnames = c("A","B")

df %>% rename_at(vars(oldnames), ~ newnames)

#  A w B
#1 1 2 3

LD Nicolas May schlug vor, eine Änderung durch rename_atfolgende zu ersetzen rename_with:

df %>% 
  rename_with(~ newnames[which(oldnames == .x)], .cols = oldnames)

#  A w B
#1 1 2 3

2
Der Benutzer fragte nach Übergabe oldund newNamen als Vektoren, denke ich
JelenaČuklina

4
Danke @ Jelena-bioinf. Ich habe die Antwort geändert, um Ihren Vorschlag aufzunehmen.
Gorka

Könnten Sie bitte die Bedeutung von ~ (Tilde) erklären und woher ".x" im Beispiel "rename_with" kommt?
Petzi

rename_withSie können entweder eine Funktion oder eine Formel verwenden, um alle als .colsArgument angegebenen Spalten umzubenennen . Zum Beispiel rename_with(iris, toupper, starts_with("Petal"))ist äquivalent zu rename_with(iris, ~ toupper(.x), starts_with("Petal")).
Paul Rougieux vor

38

Eine andere Lösung für Datenrahmen, die nicht zu groß sind, ist (basierend auf der Antwort von @thelatemail):

x <- data.frame(q=1,w=2,e=3)

> x
  q w e
1 1 2 3

colnames(x) <- c("A","w","B")

> x
  A w B
1 1 2 3

Alternativ können Sie auch Folgendes verwenden:

names(x) <- c("C","w","D")

> x
  C w D
1 1 2 3

Darüber hinaus können Sie auch eine Teilmenge der Spaltennamen umbenennen:

names(x)[2:3] <- c("E","F")

> x
  C E F
1 1 2 3

24

Hier ist die effizienteste Methode, die ich gefunden habe, um mehrere Spalten mit einer Kombination aus purrr::set_names()und einigen stringrOperationen umzubenennen .

library(tidyverse)

# Make a tibble with bad names
data <- tibble(
    `Bad NameS 1` = letters[1:10],
    `bAd NameS 2` = rnorm(10)
)

data 
# A tibble: 10 x 2
   `Bad NameS 1` `bAd NameS 2`
   <chr>                 <dbl>
 1 a                    -0.840
 2 b                    -1.56 
 3 c                    -0.625
 4 d                     0.506
 5 e                    -1.52 
 6 f                    -0.212
 7 g                    -1.50 
 8 h                    -1.53 
 9 i                     0.420
 10 j                     0.957

# Use purrr::set_names() with annonymous function of stringr operations
data %>%
    set_names(~ str_to_lower(.) %>%
                  str_replace_all(" ", "_") %>%
                  str_replace_all("bad", "good"))

# A tibble: 10 x 2
   good_names_1 good_names_2
   <chr>               <dbl>
 1 a                  -0.840
 2 b                  -1.56 
 3 c                  -0.625
 4 d                   0.506
 5 e                  -1.52 
 6 f                  -0.212
 7 g                  -1.50 
 8 h                  -1.53 
 9 i                   0.420
10 j                   0.957

6
Dies sollte die Antwort sein, aber könnten Sie wahrscheinlich auch erweitern, was die ~und .Argumente in der set_names()Pipe tun.
DaveRGP

In einigen Fällen müssen Sie explizit eingeben purrr::set_names().
Levi Baguley

1
@ DaveRGP Bei Verwendung von purrrFunktionen ~bedeutet die Tilde "für jede Spalte". Das .ist dplyr Syntax für LHS = linke Seite des Rohres, also die Referenz auf das Objekt , das geleitet wird, in diesem Fall data.
Agile Bean

Die Tilde ~ist eine Formel. Sie können auch einen Funktionsaufruf verwenden und die Argumente an das ...Argument übergeben, das set_namesbeispielsweise rlang::set_names(head(iris), paste0, "_hi")entspricht rlang::set_names(head(iris), ~ paste0(.x, "_hi")).
Paul Rougieux vor

11

Ich bin kürzlich selbst darauf gestoßen, wenn Sie nicht sicher sind, ob die Spalten vorhanden sind, und nur diejenigen umbenennen möchten, die dies tun:

existing <- match(oldNames,names(x))
names(x)[na.omit(existing)] <- newNames[which(!is.na(existing))]

6

Aufbauend auf der Antwort von @ user3114046:

x <- data.frame(q=1,w=2,e=3)
x
#  q w e
#1 1 2 3

names(x)[match(oldnames,names(x))] <- newnames

x
#  A w B
#1 1 2 3

Dies hängt nicht von einer bestimmten Reihenfolge der Spalten im xDataset ab.


1
Ich habe Ihre Antwort positiv bewertet, aber ich frage mich immer noch, ob es einen noch eleganteren Weg gibt, dies zu tun, insbesondere Methoden, die nach Namen anstatt nach Position umbenennen
qoheleth

@qoheleth - es wird nach Namen umbenannt! Es gibt hier keine Eingabe, die ein Positionsvektor ist, der matchsich darum kümmert. Das Beste, was Sie tun werden, ist wahrscheinlich die setnamesAntwort von @ mnel .
E-Mail

1
Es wird immer noch nach Position umbenannt, da es, wie Sie sagten, matchimmer noch ein positionsorientierter Befehl ist , obwohl ich keinen Positionsvektor explizit angeben muss . In diesem Sinne habe ich auch die Antwortposition von @ user3114046 als basiert angesehen (obwohl ich dachte, der %in%Befehl kümmert sich um die Dinge (oder versucht es)). Natürlich können Sie argumentieren, dass alle Befehle positionsorientiert sind, wenn wir uns mit dem Mechanismus auf niedriger Ebene befassen ... aber das meine ich nicht ... die Antwort auf die Datentabelle ist großartig, da es keine Mehrfachaufrufe von gibt nameBefehle.
Qoheleth

4

Dies würde alle Vorkommen dieser Buchstaben in allen Namen ändern:

 names(x) <- gsub("q", "A", gsub("e", "B", names(x) ) )

2
Ich denke nicht, dass dies besonders elegant ist, wenn Sie einige Umbenennungsinstanzen hinter sich haben.
E-Mail

Ich bin einfach nicht gut genug, um eine gsubfnAntwort zu finden. Vielleicht kommt G.Grothendieck vorbei. Er ist der Regex-Meister.
IRTFM

4
names(x)[names(x) %in% c("q","e")]<-c("A","B")

2
Nicht ganz, denn wie gesagt, ich kenne die Position der Spalten nicht unbedingt. Ihre Lösung funktioniert nur, wenn sie oldnamesso sortiert ist, dass sie oldnames[i]zuvor oldnames[j]für i <j auftritt .
Qoheleth

2

Sie können den Namen festlegen, als Liste speichern und dann die Massenumbenennung für die Zeichenfolge vornehmen. Ein gutes Beispiel hierfür ist, wenn Sie einen langen bis breiten Übergang für einen Datensatz durchführen:

names(labWide)
      Lab1    Lab10    Lab11    Lab12    Lab13    Lab14    Lab15    Lab16
1 35.75366 22.79493 30.32075 34.25637 30.66477 32.04059 24.46663 22.53063

nameVec <- names(labWide)
nameVec <- gsub("Lab","LabLat",nameVec)

names(labWide) <- nameVec
"LabLat1"  "LabLat10" "LabLat11" "LabLat12" "LabLat13" "LabLat14""LabLat15"    "LabLat16" " 

2

Nebenbei bemerkt, wenn Sie eine Zeichenfolge mit allen Spaltennamen verknüpfen möchten, können Sie einfach diesen einfachen Code verwenden.

colnames(df) <- paste("renamed_",colnames(df),sep="")

2

Wenn die Tabelle zwei Spalten mit demselben Namen enthält, lautet der Code folgendermaßen:

rename(df,newname=oldname.x,newname=oldname.y)

2

Sie können einen benannten Vektor verwenden.

Mit Basis R (vielleicht etwas klobig):

x = data.frame(q = 1, w = 2, e = 3) 

rename_vec <- c(q = "A", e = "B")

names(x) <- ifelse(is.na(rename_vec[names(x)]), names(x), rename_vec[names(x)])

x
#>   A w B
#> 1 1 2 3

Oder eine dplyrOption mit !!!:

library(dplyr)

rename_vec <- c(A = "q", B = "e") # the names are just the other way round than in the base R way!

x %>% rename(!!!rename_vec)
#>   A w B
#> 1 1 2 3

Letzteres funktioniert, weil der 'Big-Bang'- Operator !!!die Auswertung einer Liste oder eines Vektors erzwingt.

?`!!`

!!! Erzwingt das Spleißen einer Liste von Objekten. Die Elemente der Liste werden an Ort und Stelle zusammengefügt, was bedeutet, dass sie jeweils zu einem einzigen Argument werden.


Ich verstehe nicht, wie das funktioniert - !!!oldnameskehrt zurück, c("A", "B")aber in welche Logik wird dies umgewandelt c("A", "w", "B")?
Agile Bean

@AgileBean Ich weiß nicht, wo du das gefunden hast !!! alte Namen würden einen Vektor zurückgeben. Es wird verwendet, um eine nicht standardmäßige Auswertung mehrerer Argumente in dplyr zu erzwingen. siehe ?`!!` Use `!!!` to add multiple arguments to a function. Its argument should evaluate to a list or vector: args <- list(1:3, na.rm = TRUE) ; quo(mean(!!!args)). Ich denke, ich werde diese Erklärung der Antwort hinzufügen. Prost auf das
Thema

1

Viele Antworten, also habe ich gerade die Funktion geschrieben, damit Sie sie kopieren / einfügen können.

rename <- function(x, old_names, new_names) {
    stopifnot(length(old_names) == length(new_names))
    # pull out the names that are actually in x
    old_nms <- old_names[old_names %in% names(x)]
    new_nms <- new_names[old_names %in% names(x)]

    # call out the column names that don't exist
    not_nms <- setdiff(old_names, old_nms)
    if(length(not_nms) > 0) {
        msg <- paste(paste(not_nms, collapse = ", "), 
            "are not columns in the dataframe, so won't be renamed.")
        warning(msg)
    }

    # rename
    names(x)[names(x) %in% old_nms] <- new_nms
    x
}

 x = data.frame(q = 1, w = 2, e = 3)
 rename(x, c("q", "e"), c("Q", "E"))

   Q w E
 1 1 2 3

rename(x, c("q", "e"), c("Q", "E"))scheint nicht mehr in dplyr umbenennen zu funktionieren?
Sindri_baldur

0

Wenn eine Zeile der Daten die Namen enthält, in die Sie alle Spalten ändern möchten, können Sie dies tun

names(data) <- data[row,]

Gegeben dataist der Datenrahmen und rowdie Zeilennummer die neuen Werte enthält.

Dann können Sie die Zeile mit den Namen mit entfernen

data <- data[-row,]

0

Dies ist die Funktion, die Sie benötigen: Übergeben Sie dann einfach das x in einer Umbenennung (X) und es werden alle angezeigten Werte umbenannt. Wenn es nicht vorhanden ist, tritt kein Fehler auf

rename <-function(x){
  oldNames = c("a","b","c")
  newNames = c("d","e","f")
  existing <- match(oldNames,names(x))
  names(x)[na.omit(existing)] <- newNames[which(!is.na(existing))]
  return(x)
}

1
Dies scheint die gleiche zu sein wie JoelKuipers Antwort , wurde dann aber als Funktion umformuliert .....
Jaap

0

Es gibt einige Antworten, die die Funktionen erwähnen dplyr::rename_withund rlang::set_namesbereits. Durch sie sind getrennt. Diese Antwort zeigt die Unterschiede zwischen den beiden und die Verwendung von Funktionen und Formeln zum Umbenennen von Spalten.

rename_withaus dem dplyrPaket kann entweder eine Funktion oder eine Formel verwenden, um eine Auswahl von Spalten umzubenennen, die als .colsArgument angegeben sind. Zum Beispiel den Funktionsnamen übergeben toupper:

library(dplyr)
rename_with(head(iris), toupper, starts_with("Petal"))

Entspricht der Übergabe der Formel ~ toupper(.x):

rename_with(head(iris), ~ toupper(.x), starts_with("Petal"))

Wenn Sie alle Spalten umbenennen, können Sie sie auch set_namesaus dem rlang-Paket verwenden. Um ein anderes Beispiel zu erstellen, verwenden wir paste0als Umbenennungsfunktion. pasteOnimmt 2 Argumente an, daher gibt es verschiedene Möglichkeiten, das zweite Argument zu übergeben, je nachdem, ob wir eine Funktion oder eine Formel verwenden.

rlang::set_names(head(iris), paste0, "_hi")
rlang::set_names(head(iris), ~ paste0(.x, "_hi"))

Dasselbe kann erreicht rename_withwerden, indem der Datenrahmen als erstes Argument .data, die Funktion als zweites Argument .fn, alle Spalten als drittes Argument .cols=everything()und die Funktionsparameter als viertes Argument übergeben werden .... Alternativ können Sie das zweite, dritte und vierte Argument in eine Formel einfügen, die als zweites Argument angegeben wird.

rename_with(head(iris), paste0, everything(), "_hi")
rename_with(head(iris), ~ paste0(.x, "_hi"))

rename_withfunktioniert nur mit Datenrahmen. set_namesist allgemeiner und kann auch Vektorumbenennungen durchführen

rlang::set_names(1:4, c("a", "b", "c", "d"))
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.