Wenn ich Ihre Frage richtig verstehe, gibt es vier Methoden, um das Äquivalent zu Excel zu erreichen VLOOKUP
und Folgendes auszufüllen R
:
hous <- read.table(header = TRUE,
stringsAsFactors = FALSE,
text="HouseType HouseTypeNo
Semi 1
Single 2
Row 3
Single 2
Apartment 4
Apartment 4
Row 3")
largetable <- data.frame(HouseType = as.character(sample(unique(hous$HouseType), 1000, replace = TRUE)), stringsAsFactors = FALSE)
lookup <- unique(hous)
HouseType HouseTypeNo
1 Semi 1
2 Single 2
3 Row 3
5 Apartment 4
Hier sind vier Methoden, um HouseTypeNo
das largetable
mit den Werten in der lookup
Tabelle auszufüllen :
Zuerst mit merge
in Basis:
base1 <- (merge(lookup, largetable, by = 'HouseType'))
Eine zweite Methode mit benannten Vektoren in der Basis:
housenames <- as.numeric(1:length(unique(hous$HouseType)))
names(housenames) <- unique(hous$HouseType)
base2 <- data.frame(HouseType = largetable$HouseType,
HouseTypeNo = (housenames[largetable$HouseType]))
Drittens mit dem plyr
Paket:
library(plyr)
plyr1 <- join(largetable, lookup, by = "HouseType")
Viertens mit dem sqldf
Paket
library(sqldf)
sqldf1 <- sqldf("SELECT largetable.HouseType, lookup.HouseTypeNo
FROM largetable
INNER JOIN lookup
ON largetable.HouseType = lookup.HouseType")
Wenn es möglich ist, dass einige Haustypen in largetable
nicht vorhanden sind, lookup
wird ein linker Join verwendet:
sqldf("select * from largetable left join lookup using (HouseType)")
Entsprechende Änderungen an den anderen Lösungen wären ebenfalls erforderlich.
Wolltest du das tun? Lassen Sie mich wissen, welche Methode Ihnen gefällt, und ich werde einen Kommentar hinzufügen.
Ich denke, Sie können auch verwenden
match()
:Dies funktioniert immer noch, wenn ich die Reihenfolge von verschlüssele
lookup
.quelle
Ich benutze auch gerne einen
qdapTools::lookup
binären Operator oder eine Kurzform%l%
. Es funktioniert identisch mit einem Excel-Lookup, akzeptiert jedoch Namensargumente, die Spaltennummern entgegengesetzt sind## Replicate Ben's data: hous <- structure(list(HouseType = c("Semi", "Single", "Row", "Single", "Apartment", "Apartment", "Row"), HouseTypeNo = c(1L, 2L, 3L, 2L, 4L, 4L, 3L)), .Names = c("HouseType", "HouseTypeNo"), class = "data.frame", row.names = c(NA, -7L)) largetable <- data.frame(HouseType = as.character(sample(unique(hous$HouseType), 1000, replace = TRUE)), stringsAsFactors = FALSE) ## It's this simple: library(qdapTools) largetable[, 1] %l% hous
quelle
Lösung 2 von @ Bens Antwort ist in anderen allgemeineren Beispielen nicht reproduzierbar. Es passiert die richtige Lookup im Beispiel zu geben , weil die einzigartigen
HouseType
inhouses
aufsteigender Reihenfolge erscheinen. Versuche dies:hous <- read.table(header = TRUE, stringsAsFactors = FALSE, text="HouseType HouseTypeNo Semi 1 ECIIsHome 17 Single 2 Row 3 Single 2 Apartment 4 Apartment 4 Row 3") largetable <- data.frame(HouseType = as.character(sample(unique(hous$HouseType), 1000, replace = TRUE)), stringsAsFactors = FALSE) lookup <- unique(hous)
Bens Lösung # 2 gibt
housenames <- as.numeric(1:length(unique(hous$HouseType))) names(housenames) <- unique(hous$HouseType) base2 <- data.frame(HouseType = largetable$HouseType, HouseTypeNo = (housenames[largetable$HouseType]))
Welches wann
unique(base2$HouseTypeNo[ base2$HouseType=="ECIIsHome" ]) [1] 2
wenn die richtige Antwort 17 aus der Nachschlagetabelle ist
Der richtige Weg ist es
hous <- read.table(header = TRUE, stringsAsFactors = FALSE, text="HouseType HouseTypeNo Semi 1 ECIIsHome 17 Single 2 Row 3 Single 2 Apartment 4 Apartment 4 Row 3") largetable <- data.frame(HouseType = as.character(sample(unique(hous$HouseType), 1000, replace = TRUE)), stringsAsFactors = FALSE) housenames <- tapply(hous$HouseTypeNo, hous$HouseType, unique) base2 <- data.frame(HouseType = largetable$HouseType, HouseTypeNo = (housenames[largetable$HouseType]))
Jetzt werden die Suchvorgänge korrekt durchgeführt
unique(base2$HouseTypeNo[ base2$HouseType=="ECIIsHome" ]) ECIIsHome 17
Ich habe versucht, die Antwort von Bens zu bearbeiten, aber sie wird aus Gründen abgelehnt, die ich nicht verstehen kann.
quelle
Beginnen mit:
houses <- read.table(text="Semi 1 Single 2 Row 3 Single 2 Apartment 4 Apartment 4 Row 3",col.names=c("HouseType","HouseTypeNo"))
... können Sie verwenden
... um für jeden Haustyp eine eindeutige Nummer zu vergeben. Sie können das Ergebnis hier sehen:
> houses2 <- data.frame(houses,as.numeric(factor(houses$HouseType))) > houses2 HouseType HouseTypeNo as.numeric.factor.houses.HouseType.. 1 Semi 1 3 2 Single 2 4 3 Row 3 2 4 Single 2 4 5 Apartment 4 1 6 Apartment 4 1 7 Row 3 2
... so dass Sie am Ende unterschiedliche Zahlen in den Zeilen haben (weil die Faktoren alphabetisch geordnet sind), aber dasselbe Muster.
(BEARBEITEN: Der verbleibende Text in dieser Antwort ist tatsächlich überflüssig. Mir fiel ein, dies zu überprüfen, und es stellte sich heraus, dass
read.table()
Häuser $ HouseType bereits zu einem Faktor geworden waren, als es überhaupt in den Datenrahmen eingelesen wurde.)Es ist jedoch möglicherweise besser, HouseType in einen Faktor umzuwandeln, der Ihnen dieselben Vorteile wie HouseTypeNo bietet, aber einfacher zu interpretieren ist, da die Haustypen eher benannt als nummeriert sind, z.
> houses3 <- houses > houses3$HouseType <- factor(houses3$HouseType) > houses3 HouseType HouseTypeNo 1 Semi 1 2 Single 2 3 Row 3 4 Single 2 5 Apartment 4 6 Apartment 4 7 Row 3 > levels(houses3$HouseType) [1] "Apartment" "Row" "Semi" "Single"
quelle
Das Poster hat nicht nach dem
exact=FALSE
Nachschlagen von Werten gefragt , aber ich füge dies als Antwort für meine eigene Referenz und möglicherweise für andere hinzu.Wenn Sie nach kategorialen Werten suchen, verwenden Sie die anderen Antworten.
Mit Excel
vlookup
können Sie auch die Übereinstimmung für numerische Werte ungefähr mit dem 4. Argument (1) abgleichenmatch=TRUE
. Ich denke daranmatch=TRUE
, Werte auf einem Thermometer nachzuschlagen. Der Standardwert ist FALSE, was perfekt für kategoriale Werte ist.Wenn Sie ungefähr übereinstimmen möchten (eine Suche durchführen), hat R eine Funktion namens
findInterval
, die (wie der Name schon sagt) das Intervall / den Bin findet, das Ihren fortlaufenden numerischen Wert enthält.Angenommen, Sie möchten
findInterval
für mehrere Werte. Sie können eine Schleife schreiben oder eine Apply-Funktion verwenden. Ich habe es jedoch effizienter gefunden, einen vektorisierten DIY-Ansatz zu wählen.Angenommen, Sie haben ein durch x und y indiziertes Wertegitter:
grid <- list(x = c(-87.727, -87.723, -87.719, -87.715, -87.711), y = c(41.836, 41.839, 41.843, 41.847, 41.851), z = (matrix(data = c(-3.428, -3.722, -3.061, -2.554, -2.362, -3.034, -3.925, -3.639, -3.357, -3.283, -0.152, -1.688, -2.765, -3.084, -2.742, 1.973, 1.193, -0.354, -1.682, -1.803, 0.998, 2.863, 3.224, 1.541, -0.044), nrow = 5, ncol = 5)))
und Sie haben einige Werte, die Sie mit x und y nachschlagen möchten:
df <- data.frame(x = c(-87.723, -87.712, -87.726, -87.719, -87.722, -87.722), y = c(41.84, 41.842, 41.844, 41.849, 41.838, 41.842), id = c("a", "b", "c", "d", "e", "f")
Hier ist das visualisierte Beispiel:
contour(grid) points(df$x, df$y, pch=df$id, col="blue", cex=1.2)
Sie können die x-Intervalle und y-Intervalle mit dieser Art von Formel finden:
xrng <- range(grid$x) xbins <- length(grid$x) -1 yrng <- range(grid$y) ybins <- length(grid$y) -1 df$ix <- trunc( (df$x - min(xrng)) / diff(xrng) * (xbins)) + 1 df$iy <- trunc( (df$y - min(yrng)) / diff(yrng) * (ybins)) + 1
Sie können noch einen Schritt weiter gehen und eine (vereinfachte) Interpolation der z-Werte
grid
wie folgt durchführen:df$z <- with(df, (grid$z[cbind(ix, iy)] + grid$z[cbind(ix + 1, iy)] + grid$z[cbind(ix, iy + 1)] + grid$z[cbind(ix + 1, iy + 1)]) / 4)
Welches gibt Ihnen diese Werte:
contour(grid, xlim = range(c(grid$x, df$x)), ylim = range(c(grid$y, df$y))) points(df$x, df$y, pch=df$id, col="blue", cex=1.2) text(df$x + .001, df$y, lab=round(df$z, 2), col="blue", cex=1)
df # x y id ix iy z # 1 -87.723 41.840 a 2 2 -3.00425 # 2 -87.712 41.842 b 4 2 -3.11650 # 3 -87.726 41.844 c 1 3 0.33150 # 4 -87.719 41.849 d 3 4 0.68225 # 6 -87.722 41.838 e 2 1 -3.58675 # 7 -87.722 41.842 f 2 2 -3.00425
Beachten Sie, dass ix und iy auch mit einer Schleife gefunden werden könnten
findInterval
, z. B. hier ein Beispiel für die zweite ZeilefindInterval(df$x[2], grid$x) # 4 findInterval(df$y[2], grid$y) # 2
Welche Spiele
ix
undiy
indf[2]
Fußnote: (1) Das vierte Argument von vlookup hieß zuvor "match", wurde jedoch nach Einführung des Menübands in "[range_lookup]" umbenannt.
quelle
Sie können
mapvalues()
aus dem Plyr-Paket verwenden.Anfangsdaten:
dat <- data.frame(HouseType = c("Semi", "Single", "Row", "Single", "Apartment", "Apartment", "Row")) > dat HouseType 1 Semi 2 Single 3 Row 4 Single 5 Apartment 6 Apartment 7 Row
Lookup / Zebrastreifen Tisch:
lookup <- data.frame(type_text = c("Semi", "Single", "Row", "Apartment"), type_num = c(1, 2, 3, 4)) > lookup type_text type_num 1 Semi 1 2 Single 2 3 Row 3 4 Apartment 4
Erstellen Sie die neue Variable:
Oder für einfache Ersetzungen können Sie das Erstellen einer langen Nachschlagetabelle überspringen und dies direkt in einem Schritt tun:
dat$house_type_num <- plyr::mapvalues(dat$HouseType, from = c("Semi", "Single", "Row", "Apartment"), to = c(1, 2, 3, 4))
Ergebnis:
> dat HouseType house_type_num 1 Semi 1 2 Single 2 3 Row 3 4 Single 2 5 Apartment 4 6 Apartment 4 7 Row 3
quelle
Die Verwendung
merge
unterscheidet sich von der Suche in Excel, da sie möglicherweise Ihre Daten dupliziert (multipliziert), wenn die Primärschlüsseleinschränkung in der Nachschlagetabelle nicht erzwungen wird, oder die Anzahl der Datensätze verringert, wenn Sie sie nicht verwendenall.x = T
.Um sicherzustellen, dass Sie damit nicht in Schwierigkeiten geraten und sicher nachschlagen, schlage ich zwei Strategien vor.
Zunächst müssen Sie eine Reihe von doppelten Zeilen im Suchschlüssel überprüfen:
safeLookup <- function(data, lookup, by, select = setdiff(colnames(lookup), by)) { # Merges data to lookup making sure that the number of rows does not change. stopifnot(sum(duplicated(lookup[, by])) == 0) res <- merge(data, lookup[, c(by, select)], by = by, all.x = T) return (res) }
Dadurch werden Sie gezwungen, das Lookup-Dataset zu deaktivieren, bevor Sie es verwenden:
baseSafe <- safeLookup(largetable, house.ids, by = "HouseType") # Error: sum(duplicated(lookup[, by])) == 0 is not TRUE baseSafe<- safeLookup(largetable, unique(house.ids), by = "HouseType") head(baseSafe) # HouseType HouseTypeNo # 1 Apartment 4 # 2 Apartment 4 # ...
Die zweite Option besteht darin, das Excel-Verhalten zu reproduzieren, indem der erste übereinstimmende Wert aus dem Suchdatensatz übernommen wird:
firstLookup <- function(data, lookup, by, select = setdiff(colnames(lookup), by)) { # Merges data to lookup using first row per unique combination in by. unique.lookup <- lookup[!duplicated(lookup[, by]), ] res <- merge(data, unique.lookup[, c(by, select)], by = by, all.x = T) return (res) } baseFirst <- firstLookup(largetable, house.ids, by = "HouseType")
Diese Funktionen unterscheiden sich geringfügig von denen,
lookup
da sie mehrere Spalten hinzufügen.quelle