Yanıtlar:
rbind.fillpaketten plyraradığınız şey olabilir.
Daha yeni bir çözüm kullanmaktır dplyr'ın bind_rowsı daha etkili olduğunu varsayalım fonksiyonu 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
ABCkarakterden sayısal dönüştürülemez. İlk önce sütunları dönüştürmenin bir yolu var mı?
Sen kullanabilirsiniz smartbindgelen gtoolspaketin.
Misal:
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İki büyük veri çerçevesi ile denedim (toplamda yaklaşık 3 * 10 ^ 6 satır) ve 10 dakika sonra iptal ettim.
Sütun halinde df1 içinde bir alt kümesi olup df2 (sütun adlarıyla):
df3 <- rbind(df1, df2[, names(df1)])
Alternatifi 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)
rbindAyrıca çalışacak data.tablenesneler dönüştürülür sürece data.tablenesneler, böylece
rbind(setDT(df1), setDT(df2), fill=TRUE)
bu durumda da çalışacaktır. Birkaç data.tabare varsa ve bir liste oluşturmak istemiyorsanız bu tercih edilebilir.
intersectYaklaşım gibi diğer cevaplar sadece 2 veri çerçevesi için çalışır ve kolayca genelleştirilmez.
Temel R cevaplarının çoğu, yalnızca bir data.frame'in ek sütunlara sahip olduğu veya elde edilen data.frame'in sütunların kesişimine sahip olacağı durumu ele alır. OP , bağlamadan sonra eşleşmeyen sütunları tutmayı umduğumu yazdığından , bu sorunu gidermek için temel R yöntemlerini kullanan bir yanıt muhtemelen göndermeye değer.
Aşağıda, iki temel R yöntemi sunuyorum: Biri orijinal verileri değiştiriyor. Çerçeveler ve diğeri değişmiyor. Ayrıca, tahribatsız yöntemi ikiden fazla data.frames için genelleştiren bir yöntem sunuyoruz.
İlk olarak, bazı örnek veriler elde edelim.
# 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])
İki data.frames, orijinali değiştirme
Her iki data.frames öğesindeki tüm sütunları bir rbind(ve işlevin hata vermeden çalışmasına izin vermek) için, her data.frame öğesine NA sütunları ekleyerek uygun eksik adlar doldurulur kullanarak setdiff.
# fill in non-overlapping columns with NAs
df1[setdiff(names(df2), names(df1))] <- NA
df2[setdiff(names(df1), names(df2))] <- NA
Şimdi, 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
İlk iki satırın orijinal verileri değiştirdiğini unutmayın. Çerçeveler, df1 ve df2, her ikisine de tüm sütun kümesini ekler.
İki data.frames, orijinalleri değiştirmeyin Orijinal data.frames'i olduğu gibi
bırakmak için, önce farklı adlar arasında döngü yapın, data.frame kullanarak bir listeye birleştirilen adlandırılmış bir NA vektörü döndürün c. Ardından, data.framesonucu için uygun bir veri çerçevesine dönüştürür 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)))
)
Birçok data.frames, orijinalleri değiştirmeyin
İkiden fazla data.frames olması durumunda, aşağıdakileri yapabilirsiniz.
# 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)))))
Belki orijinal data.frames satır adlarını görmek için biraz daha hoş? O zaman bunu yap.
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). Bu, ortamınızın boyutunu büyütmeyen, ancak yalnızca listenin her öğesini işaret eden bir liste nesnesi oluşturmalıdır (daha sonra içeriğin hiçbirini değiştirmediğiniz sürece). İşlemden sonra, sadece güvende olmak için liste nesnesini kaldırın.
Ayrıca, ortak sütun adlarını da çıkarabilirsiniz.
> cols <- intersect(colnames(df1), colnames(df2))
> rbind(df1[,cols], df2[,cols])
Bunu yapmak için bir işlev yazdım, çünkü kodumun bir şeylerin yanlış olup olmadığını anlatmasını seviyorum. Bu işlev, hangi sütun adlarının eşleşmediğini ve tür uyuşmazlığınız olup olmadığını açıkça söyleyecektir. Daha sonra verileri birleştirmek için elinden geleni yapacaktır. Yine de çerçeveler. Sınırlama, aynı anda yalnızca iki veri çerçevesini birleştirebilmenizdir.
### 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)
}
Belki sorunuzu tamamen yanlış okudum, ancak "Bağlandıktan sonra eşleşmeyen sütunları tutmayı umuyorum" bana bir SQL sorgusu left joinveya right joinbenzeri bir şey aradığınızı düşündürüyor . R, mergeSQL'deki tabloları birleştirmeye benzer şekilde sol, sağ veya iç birleşimleri belirtmenize izin veren işleve sahiptir .
Burada zaten bu konuda büyük bir soru ve cevap var: Veri çerçevelerine (iç, dış, sol, sağ) nasıl birleştirilir (birleştirilir)?
gtools / smartbind, muhtemelen tarih olduğu için Tarihlerle çalışmayı sevmiyordu. İşte benim çözümüm ...
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)
}
Sadece belgeler için. StackKitaplığı ve işlevini Stackaşağıdaki biçimde deneyebilirsiniz :
Stack(df_1, df_2)
Ayrıca büyük veri kümeleri için diğer yöntemlerden daha hızlı olduğu izlenim var.
Ayrıca kullanabilirsiniz sjmisc::add_rows()hangi kullanımları dplyr::bind_rows(), ancak aksine bind_rows(), add_rows()korur nitelikleri ve dolayısıyla için yararlıdır etiketli veriler .
Etiketli veri kümesiyle aşağıdaki örneğe bakın. frq()Taşımasının avantajlı, değeri etiketlerle frekans tabloları basar ise veri etiketlenir.
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.fillvebind_rows()her ikisi de sessizce rownames bırakır.