Ersetzen Sie einen Wert in einem Datenrahmen basierend auf einer bedingten (`if`) Anweisung


122

In dem unten codierten R-Datenrahmen möchte ich alle Zeiten ersetzen, die durch B angezeigt werden b.

junk <- data.frame(x <- rep(LETTERS[1:4], 3), y <- letters[1:12])
colnames(junk) <- c("nm", "val")

Dies bietet:

   nm val
1   A   a
2   B   b
3   C   c
4   D   d
5   A   e
6   B   f
7   C   g
8   D   h
9   A   i
10  B   j
11  C   k
12  D   l

Mein erster Versuch war, a forund ifAnweisungen wie folgt zu verwenden:

for(i in junk$nm) if(i %in% "B") junk$nm <- "b"

Aber wie Sie sicher sehen können, ersetzt dies ALLE Werte von junk$nmdurch b. Ich kann sehen, warum dies so ist, aber ich kann nicht scheinen, dass es nur die Fälle von Junk $ nm ersetzt, in denen der ursprüngliche Wert war B.

HINWEIS: Ich habe es geschafft, das Problem mit zu lösen, gsubaber im Interesse des Lernens möchte RI immer noch wissen, wie ich meinen ursprünglichen Ansatz zum Arbeiten bringen kann (wenn es möglich ist).


1
Möglicherweise möchten Sie der ursprünglichen data.frame-Konstruktion stringsAsFactors = FALSE hinzufügen.
Jimmyb

@ Jimmyb Warum? Faktoren sind nützlich und notwendig, wenn mit dem größten Teil des Modellierungscodes von R modelliert wird. Der richtige Weg, damit umzugehen, besteht darin, anzuerkennen, dass die Daten ein Faktor sind. Wenn Sie diese Konvertierung nicht möchten / brauchen, können Sie tun, was Sie sagen. Wenn Sie den Faktor möchten, gibt es einfache Möglichkeiten, die Manipulation durchzuführen, die @Kenny ausführen möchte.
Gavin Simpson

1
Früher waren Faktoren aufgrund der Leistung populärer, jetzt, da Zeichenfolgen unveränderlich sind und den Wert von Faktoren gehasht haben, ist dies weniger offensichtlich, da die meisten Basis-R-Funktionen sie nur (wenn auch mit Warnungen) direkt konvertieren. Ich denke, Faktoren führen zu einer signifikanten Anzahl von Fehlern, die ich im R-Code der Leute finde.
Jimmyb

Antworten:


217

Einfacher, nm in Zeichen umzuwandeln und dann die Änderung vorzunehmen:

junk$nm <- as.character(junk$nm)
junk$nm[junk$nm == "B"] <- "b"

EDIT: Und wenn Sie tatsächlich nm als Faktoren beibehalten müssen, fügen Sie dies am Ende hinzu:

junk$nm <- as.factor(junk$nm)

4
as.character () erleichtert das Leben beim Umgang mit Faktoren erheblich. +1
Brandon Bertelsen

4
Was ist, wenn Sie mehrere Spalten haben?
Geodex

43

Ein weiterer nützlicher Weg, um Werte zu ersetzen

library(plyr)
junk$nm <- revalue(junk$nm, c("B"="b"))

25

Kurze Antwort lautet:

junk$nm[junk$nm %in% "B"] <- "b"

Schauen Sie sich die Indexvektoren in R Einführung an (falls Sie sie noch nicht gelesen haben).


BEARBEITEN. Wie in den Kommentaren erwähnt, funktioniert diese Lösung für Zeichenvektoren, sodass Ihre Daten nicht funktionieren.

Für Faktor ist der beste Weg, das Level zu ändern:

levels(junk$nm)[levels(junk$nm)=="B"] <- "b"

Kurzer Zusatz: Die Verwendung von% in% hilft nur dann wirklich, wenn Sie ein Set auf der rechten Seite haben, wie c("B","C"). Tun junk$nm[junk$nm == "B"]ist der bessere Weg.
Thilo

1
Oh, eine weitere wichtige Ergänzung: Um dies zu tun, muss zuerst bder Faktor nm zum Faktor nm addiert werden . Die Version von diliop ist in der Tat die bessere, wenn Sie mit Charakteren arbeiten möchten, nicht mit Faktoren. (Denken Sie immer zuerst an den Typ Ihrer Variablen!)
Thilo

Das funktioniert nicht mit den von @Kenny erstellten Daten, da die Daten Faktoren sind. Haben Sie einen Schritt vergessen oder haben Sie die globale Einstellung, um die Konvertierung von Zeichen in Faktoren zu beenden?
Gavin Simpson

4
@Thilo Einer der wichtigsten Unterschiede zwischen %in%und ==ist die NAHandhabung: c(1,2,NA)==1gibt TRUE, FALSE, NAaber c(1,2,NA) %in% 1gibt TRUE, FALSE, FALSE. Und ja, ich habe vergessen zu überprüfen, ob diese Arbeit: /
Marek

20

Da die von Ihnen angezeigten Daten Faktoren sind, erschwert dies die Dinge ein wenig. Die Antwort von @ diliop nähert sich dem Problem, indem sie nmin eine Zeichenvariable konvertiert . Um zu den ursprünglichen Faktoren zurückzukehren, ist ein weiterer Schritt erforderlich.

Eine Alternative besteht darin, die Ebenen des vorhandenen Faktors zu manipulieren.

> lev <- with(junk, levels(nm))
> lev[lev == "B"] <- "b"
> junk2 <- within(junk, levels(nm) <- lev)
> junk2
   nm val
1   A   a
2   b   b
3   C   c
4   D   d
5   A   e
6   b   f
7   C   g
8   D   h
9   A   i
10  b   j
11  C   k
12  D   l

Das ist ganz einfach und ich vergesse oft, dass es eine Ersatzfunktion für gibt levels().

Bearbeiten: Wie von @Seth in den Kommentaren angegeben, kann dies in einem Einzeiler ohne Verlust der Klarheit erfolgen:

within(junk, levels(nm)[levels(nm) == "B"] <- "b")

6
Nett. Ich wusste nichts über die Ersatzfunktion für levels(). Wie wäre es mit dem einen Liner junk <- within(junk, levels(nm)[levels(nm)=="B"] <- "b")?

Aber du nennst es zweimal :)
Marek

2
@Marek schlägt auf den Kopf Nur um zu zeigen, dass man nicht auf Kommentare zu SO reagieren sollte, wenn es weit nach dem Schlafengehen ist. Versuchen wir das noch einmal ...
Gavin Simpson

@ Seth In der Tat - schön. Nicht sicher, warum ich die Stufen getrennt habe? Vielleicht zur Ausstellung ...
Gavin Simpson

11

Der einfachste Weg, dies in einem Befehl zu tun, besteht darin, einen Befehl zu verwenden whichund die Faktoren auf diese Weise nicht in Zeichen umzuwandeln:

junk$nm[which(junk$nm=="B")]<-"b"

5

Sie haben eine Faktorvariable in erstellt, nmsodass Sie dies entweder vermeiden oder den Faktorattributen eine zusätzliche Ebene hinzufügen müssen. Sie sollten auch vermeiden, <-in den Argumenten zu data.frame () zu verwenden.

Option 1:

junk <- data.frame(x = rep(LETTERS[1:4], 3), y =letters[1:12], stringsAsFactors=FALSE)
junk$nm[junk$nm == "B"] <- "b"

Option 2:

levels(junk$nm) <- c(levels(junk$nm), "b")
junk$nm[junk$nm == "B"] <- "b"
junk

@ DWin danke für Ihre Eingabe zu dem Problem und die Notwendigkeit, den Variablentyp zu berücksichtigen. Ich habe die Antwort von @ diliop akzeptiert, weil es die erste funktionierende war. Ich weiß, dass es viele Probleme mit <- vs = gibt, aber (wenn es kurz beantwortet werden kann) warum sollte = verwendet werden data.frame?
DQdlM

Sie müssen nicht bals Ebene hinzufügen, sondern nur die Ebene ändern, Bauf die b.
Gavin Simpson

@KennyPeanuts: Der Spaltenname ist ein Problem a <- data.frame(x<-1:10). Sein Spaltenname ist nicht xsondern eher chaotisch x....1.10. Verwenden Sie besser data.frame (x = 1: 10). Dann wissen Sie, wie Ihr Spaltenname lautet.
IRTFM

@ Gavin: Einfacher hinzuzufügen als zu ersetzen und noch einfacher, es nicht zu einem Faktor zu machen.
IRTFM

@Dwin einfacher? Ich bin anderer Meinung - siehe meine Antwort für etwas Einfaches. Das Hinzufügen von Ebenen kann Sie beispielsweise bei der Modellierung überraschen, bei predict()der Sie sich beschweren, wenn die Faktorenebenen in neuen Daten nicht mit denen übereinstimmen, die für das Modell verwendet wurden. Auf lange Sicht sauberer, um die Daten richtig formatieren zu können, als sich auf Abkürzungen zu verlassen. Ich bin damit einverstanden, dass es vielleicht einfacher ist, es nicht zu einem Faktor zu machen, aber wenn es bereits einer ist oder einer für eine Modellierungsübung sein muss ...
Gavin Simpson

1

Wenn Sie mit Zeichenvariablen arbeiten (beachten Sie, dass dies stringsAsFactorshier falsch ist), können Sie replace verwenden:

junk <- data.frame(x <- rep(LETTERS[1:4], 3), y <- letters[1:12], stringsAsFactors = FALSE)
colnames(junk) <- c("nm", "val")

junk$nm <- replace(junk$nm, junk$nm == "B", "b")
junk
#    nm val
# 1   A   a
# 2   b   b
# 3   C   c
# 4   D   d
# ...

0
stata.replace<-function(data,replacevar,replacevalue,ifs) {
  ifs=parse(text=ifs)
  yy=as.numeric(eval(ifs,data,parent.frame()))
  x=sum(yy)
  data=cbind(data,yy)
  data[yy==1,replacevar]=replacevalue
  message=noquote(paste0(x, " replacement are made"))
  print(message)
  return(data[,1:(ncol(data)-1)])
}

Rufen Sie diese Funktion über die folgende Zeile auf.

d=stata.replace(d,"under20",1,"age<20")
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.