Antworten:
rbind.fill
aus dem Paket plyr
könnte sein, was Sie suchen.
Eine neuere Lösung besteht darin, dplyr
die bind_rows
Funktion zu verwenden , von der ich annehme, dass sie effizienter ist als smartbind
.
df1 <- data.frame(a = c(1:5), b = c(6:10))
df2 <- data.frame(a = c(11:15), b = c(16:20), c = LETTERS[1:5])
dplyr::bind_rows(df1, df2)
a b c
1 1 6 <NA>
2 2 7 <NA>
3 3 8 <NA>
4 4 9 <NA>
5 5 10 <NA>
6 11 16 A
7 12 17 B
8 13 18 C
9 14 19 D
10 15 20 E
ABC
kann nicht von Zeichen in Zahlen umgewandelt werden. Gibt es eine Möglichkeit, die Spalten zuerst zu konvertieren?
Sie können smartbind
aus dem gtools
Paket verwenden.
Beispiel:
library(gtools)
df1 <- data.frame(a = c(1:5), b = c(6:10))
df2 <- data.frame(a = c(11:15), b = c(16:20), c = LETTERS[1:5])
smartbind(df1, df2)
# result
a b c
1.1 1 6 <NA>
1.2 2 7 <NA>
1.3 3 8 <NA>
1.4 4 9 <NA>
1.5 5 10 <NA>
2.1 11 16 A
2.2 12 17 B
2.3 13 18 C
2.4 14 19 D
2.5 15 20 E
smartbind
mit zwei großen Datenrahmen (insgesamt ungefähr 3 * 10 ^ 6 Zeilen) versucht und nach 10 Minuten abgebrochen.
Wenn die Spalten in df1 eine Teilmenge der Spalten in df2 sind (nach Spaltennamen):
df3 <- rbind(df1, df2[, names(df1)])
Eine Alternative mit data.table
:
library(data.table)
df1 = data.frame(a = c(1:5), b = c(6:10))
df2 = data.frame(a = c(11:15), b = c(16:20), c = LETTERS[1:5])
rbindlist(list(df1, df2), fill = TRUE)
rbind
funktioniert data.table
auch, solange die Objekte in data.table
Objekte konvertiert werden
rbind(setDT(df1), setDT(df2), fill=TRUE)
wird auch in dieser Situation funktionieren. Dies kann vorzuziehen sein, wenn Sie über mehrere data.tables verfügen und keine Liste erstellen möchten.
intersect
Ansatz, funktionieren nur für 2 Datenrahmen und lassen sich nicht leicht verallgemeinern.
Die meisten Antworten der Basis R befassen sich mit der Situation, in der nur ein data.frame zusätzliche Spalten enthält oder der resultierende data.frame den Schnittpunkt der Spalten aufweist. Da das OP schreibt, hoffe ich, die Spalten beizubehalten, die nach dem Binden nicht übereinstimmen , ist eine Antwort mit Basis-R-Methoden zur Behebung dieses Problems wahrscheinlich eine Veröffentlichung wert.
Im Folgenden stelle ich zwei Basis-R-Methoden vor: Eine, die die ursprünglichen data.frames ändert, und eine, die dies nicht tut. Zusätzlich biete ich eine Methode an, die die zerstörungsfreie Methode auf mehr als zwei data.frames verallgemeinert.
Lassen Sie uns zunächst einige Beispieldaten abrufen.
# sample data, variable c is in df1, variable d is in df2
df1 = data.frame(a=1:5, b=6:10, d=month.name[1:5])
df2 = data.frame(a=6:10, b=16:20, c = letters[8:12])
Zwei Datenrahmen, Originale ändern
Um alle Spalten aus beiden Datenrahmen in einem zu behalten rbind
(und die Funktion ohne Fehler arbeiten zu lassen), fügen Sie jedem Datenrahmen NA-Spalten mit den entsprechenden fehlenden Namen hinzu mit setdiff
.
# fill in non-overlapping columns with NAs
df1[setdiff(names(df2), names(df1))] <- NA
df2[setdiff(names(df1), names(df2))] <- NA
Nun, rbind
-em
rbind(df1, df2)
a b d c
1 1 6 January <NA>
2 2 7 February <NA>
3 3 8 March <NA>
4 4 9 April <NA>
5 5 10 May <NA>
6 6 16 <NA> h
7 7 17 <NA> i
8 8 18 <NA> j
9 9 19 <NA> k
10 10 20 <NA> l
Beachten Sie, dass die ersten beiden Zeilen die ursprünglichen Datenrahmen df1 und df2 ändern und beiden den vollständigen Satz von Spalten hinzufügen.
Zwei data.frames, Originale nicht ändern
Um die ursprünglichen data.frames intakt zu lassen, durchlaufen Sie zunächst die unterschiedlichen Namen und geben Sie einen benannten Vektor von NAs zurück, die mit dem data.frame in einer Liste verkettet sind c
. Dann data.frame
wandelt das Ergebnis in eine entsprechende data.frame für die rbind
.
rbind(
data.frame(c(df1, sapply(setdiff(names(df2), names(df1)), function(x) NA))),
data.frame(c(df2, sapply(setdiff(names(df1), names(df2)), function(x) NA)))
)
Viele data.frames ändern Originale nicht
In dem Fall, dass Sie mehr als zwei data.frames haben, können Sie Folgendes tun.
# put data.frames into list (dfs named df1, df2, df3, etc)
mydflist <- mget(ls(pattern="df\\d+"))
# get all variable names
allNms <- unique(unlist(lapply(mydflist, names)))
# put em all together
do.call(rbind,
lapply(mydflist,
function(x) data.frame(c(x, sapply(setdiff(allNms, names(x)),
function(y) NA)))))
Vielleicht ein bisschen schöner, die Zeilennamen der ursprünglichen data.frames nicht zu sehen? Dann mach das.
do.call(rbind,
c(lapply(mydflist,
function(x) data.frame(c(x, sapply(setdiff(allNms, names(x)),
function(y) NA)))),
make.row.names=FALSE))
mydflist <- list(as, dr, kr, hyt, ed1, of)
. Dadurch sollte ein Listenobjekt erstellt werden, das nicht die Größe Ihrer Umgebung vergrößert, sondern nur auf jedes Element der Liste verweist (sofern Sie anschließend keinen Inhalt ändern). Entfernen Sie nach dem Vorgang das Listenobjekt, um die Sicherheit zu gewährleisten.
Sie können auch einfach die allgemeinen Spaltennamen herausziehen.
> cols <- intersect(colnames(df1), colnames(df2))
> rbind(df1[,cols], df2[,cols])
Ich habe eine Funktion geschrieben, um dies zu tun, weil ich möchte, dass mein Code mir sagt, wenn etwas nicht stimmt. Diese Funktion teilt Ihnen explizit mit, welche Spaltennamen nicht übereinstimmen und ob der Typ nicht übereinstimmt. Dann wird es sein Bestes tun, um die data.frames trotzdem zu kombinieren. Die Einschränkung besteht darin, dass Sie jeweils nur zwei data.frames kombinieren können.
### combines data frames (like rbind) but by matching column names
# columns without matches in the other data frame are still combined
# but with NA in the rows corresponding to the data frame without
# the variable
# A warning is issued if there is a type mismatch between columns of
# the same name and an attempt is made to combine the columns
combineByName <- function(A,B) {
a.names <- names(A)
b.names <- names(B)
all.names <- union(a.names,b.names)
print(paste("Number of columns:",length(all.names)))
a.type <- NULL
for (i in 1:ncol(A)) {
a.type[i] <- typeof(A[,i])
}
b.type <- NULL
for (i in 1:ncol(B)) {
b.type[i] <- typeof(B[,i])
}
a_b.names <- names(A)[!names(A)%in%names(B)]
b_a.names <- names(B)[!names(B)%in%names(A)]
if (length(a_b.names)>0 | length(b_a.names)>0){
print("Columns in data frame A but not in data frame B:")
print(a_b.names)
print("Columns in data frame B but not in data frame A:")
print(b_a.names)
} else if(a.names==b.names & a.type==b.type){
C <- rbind(A,B)
return(C)
}
C <- list()
for(i in 1:length(all.names)) {
l.a <- all.names[i]%in%a.names
pos.a <- match(all.names[i],a.names)
typ.a <- a.type[pos.a]
l.b <- all.names[i]%in%b.names
pos.b <- match(all.names[i],b.names)
typ.b <- b.type[pos.b]
if(l.a & l.b) {
if(typ.a==typ.b) {
vec <- c(A[,pos.a],B[,pos.b])
} else {
warning(c("Type mismatch in variable named: ",all.names[i],"\n"))
vec <- try(c(A[,pos.a],B[,pos.b]))
}
} else if (l.a) {
vec <- c(A[,pos.a],rep(NA,nrow(B)))
} else {
vec <- c(rep(NA,nrow(A)),B[,pos.b])
}
C[[i]] <- vec
}
names(C) <- all.names
C <- as.data.frame(C)
return(C)
}
Vielleicht habe ich Ihre Frage völlig falsch verstanden, aber das "Ich hoffe, die Spalten beizubehalten, die nach dem Binden nicht übereinstimmen" lässt mich denken, dass Sie nach einer left join
oder einer right join
ähnlichen SQL-Abfrage suchen . R verfügt über die merge
Funktion, mit der Sie linke, rechte oder innere Verknüpfungen angeben können, ähnlich wie beim Verknüpfen von Tabellen in SQL.
Zu diesem Thema gibt es hier bereits eine gute Frage und Antwort: Wie werden Datenrahmen (innen, außen, links, rechts) verbunden (zusammengeführt)?
gtools / smartbind arbeiteten nicht gern mit Dates, wahrscheinlich weil es as.vectoring war. Also hier ist meine Lösung ...
sbind = function(x, y, fill=NA) {
sbind.fill = function(d, cols){
for(c in cols)
d[[c]] = fill
d
}
x = sbind.fill(x, setdiff(names(y),names(x)))
y = sbind.fill(y, setdiff(names(x),names(y)))
rbind(x, y)
}
Nur zur Dokumentation. Sie können die Stack
Bibliothek und ihre Funktion Stack
in folgender Form ausprobieren :
Stack(df_1, df_2)
Ich habe auch den Eindruck, dass es schneller als andere Methoden für große Datenmengen ist.
Sie können auch verwendet werden sjmisc::add_rows()
, welche Anwendungen dplyr::bind_rows()
, aber im Gegensatz zu bind_rows()
, add_rows()
Konserven - Attribute und ist daher für sinnvoll markierte Daten .
Siehe folgendes Beispiel mit einem beschrifteten Datensatz. Die Funktion frq()
druckt Häufigkeitstabellen mit Wertelabels, wenn die Daten beschriftet sind.
library(sjmisc)
library(dplyr)
data(efc)
# select two subsets, with some identical and else different columns
x1 <- efc %>% select(1:5) %>% slice(1:10)
x2 <- efc %>% select(3:7) %>% slice(11:20)
str(x1)
#> 'data.frame': 10 obs. of 5 variables:
#> $ c12hour : num 16 148 70 168 168 16 161 110 28 40
#> ..- attr(*, "label")= chr "average number of hours of care per week"
#> $ e15relat: num 2 2 1 1 2 2 1 4 2 2
#> ..- attr(*, "label")= chr "relationship to elder"
#> ..- attr(*, "labels")= Named num 1 2 3 4 5 6 7 8
#> .. ..- attr(*, "names")= chr "spouse/partner" "child" "sibling" "daughter or son -in-law" ...
#> $ e16sex : num 2 2 2 2 2 2 1 2 2 2
#> ..- attr(*, "label")= chr "elder's gender"
#> ..- attr(*, "labels")= Named num 1 2
#> .. ..- attr(*, "names")= chr "male" "female"
#> $ e17age : num 83 88 82 67 84 85 74 87 79 83
#> ..- attr(*, "label")= chr "elder' age"
#> $ e42dep : num 3 3 3 4 4 4 4 4 4 4
#> ..- attr(*, "label")= chr "elder's dependency"
#> ..- attr(*, "labels")= Named num 1 2 3 4
#> .. ..- attr(*, "names")= chr "independent" "slightly dependent" "moderately dependent" "severely dependent"
bind_rows(x1, x1) %>% frq(e42dep)
#>
#> # e42dep <numeric>
#> # total N=20 valid N=20 mean=3.70 sd=0.47
#>
#> val frq raw.prc valid.prc cum.prc
#> 3 6 30 30 30
#> 4 14 70 70 100
#> <NA> 0 0 NA NA
add_rows(x1, x1) %>% frq(e42dep)
#>
#> # elder's dependency (e42dep) <numeric>
#> # total N=20 valid N=20 mean=3.70 sd=0.47
#>
#> val label frq raw.prc valid.prc cum.prc
#> 1 independent 0 0 0 0
#> 2 slightly dependent 0 0 0 0
#> 3 moderately dependent 6 30 30 30
#> 4 severely dependent 14 70 70 100
#> NA NA 0 0 NA NA
rbind.ordered=function(x,y){
diffCol = setdiff(colnames(x),colnames(y))
if (length(diffCol)>0){
cols=colnames(y)
for (i in 1:length(diffCol)) y=cbind(y,NA)
colnames(y)=c(cols,diffCol)
}
diffCol = setdiff(colnames(y),colnames(x))
if (length(diffCol)>0){
cols=colnames(x)
for (i in 1:length(diffCol)) x=cbind(x,NA)
colnames(x)=c(cols,diffCol)
}
return(rbind(x, y[, colnames(x)]))
}
rbind.fill
undbind_rows()
beide lassen lautlos Rownamen fallen.