Satır satır R veri çerçevesi oluşturma


108

R'de satır satır bir veri çerçevesi oluşturmak istiyorum. Biraz arama yaptım ve tüm bulduğum, boş bir liste oluşturma, bir liste endeksini tutma ve her seferinde listeye ekleme önerisi oldu. tek satırlık bir veri çerçevesi ve liste dizinini birer birer ilerletin. Son olarak do.call(rbind,)listede.

Bu işe yarasa da çok külfetli görünüyor. Aynı hedefe ulaşmanın daha kolay bir yolu yok mu?

Açıkçası, bazı applyişlevleri kullanamadığım ve açıkça veri çerçevesini satır satır oluşturmam gereken durumlara atıfta bulunuyorum . En azından, pushkullanılan son dizini açıkça takip etmek yerine bir listenin sonuna girmenin bir yolu var mı?


1
Sen kullanabilirsiniz append()[muhtemelen insert adlı olmalıdır ki] veya c()gerçi burada yardımcı olmaz, bir listenin sonuna öğeler eklemek için.
hatmatrix

Dönüş veri çerçeveleri bunları iade sürece, söz konusu Ar Birçok işlevleri yoktur [sıra sıra] den lapply(), Map()vb, ama aynı zamanda bir göz atmak isteyebilirsiniz aggregate(), dapply() {heR.Misc}ve cast() {reshape}senin görevleri bu tarafından ele alınamaz görmek için işlevler (bunların tümü veri çerçevelerini döndürür).
hatmatrix

Yanıtlar:


96

Bunları ekleyerek veya kullanarak satır satır büyütebilirsiniz rbind().

Bu yapman gerektiği anlamına gelmez. Dinamik olarak büyüyen yapılar, R'de kodlamanın en az verimli yollarından biridir.

Yapabiliyorsanız, tüm data.frame'inizi önceden ayırın:

N <- 1e4  # total number of rows to preallocate--possibly an overestimate

DF <- data.frame(num=rep(NA, N), txt=rep("", N),  # as many cols as you need
                 stringsAsFactors=FALSE)          # you don't know levels yet

ve ardından işlemleriniz sırasında her seferinde satır ekleyin

DF[i, ] <- list(1.4, "foo")

Bu keyfi data.frame için çalışmalı ve çok daha verimli olmalıdır. N'yi aşarsanız, her zaman sonunda boş satırları küçültebilirsiniz.


6
1.4'ü karakter moduna zorlamamak için 10 yerine N ve c (1.4, "foo") yerine list (1.4, "foo") koymak istemediniz mi?
hatmatrix

Evet, data.frame oluşturmada N kullanmak istedim. Ayrıca, sohbete zorlamayı çok iyi yakaladım - bunu kaçırmıştım.
Dirk Eddelbuettel

1
Yanıtı yorumlarda bırakmaktansa düzenlemek daha iyi olur. Bu cevabı alay etmeye çalışırken kafam karıştı.
Kullanıcı

4
data.tabledata.frames kullanarak ön-ayırmadan bile daha hızlı görünüyor. Burada test ediliyor: stackoverflow.com/a/11486400/636656
Ari B. Friedman

Bu, daha hızlı olması gereken R 3.1'de hala doğru mu?
userJT

49

Aşağıdakilere satırlar eklenebilir NULL:

df<-NULL;
while(...){
  #Some code that generates new row
  rbind(df,row)->df
}

Örneğin

df<-NULL
for(e in 1:10) rbind(df,data.frame(x=e,square=e^2,even=factor(e%%2==0)))->df
print(df)

3
bir veri çerçevesi değil, bir matris çıktılar
Olga

1
@Olga Yalnızca eşit türden öğelerin satırlarını bağlarsanız - BTW bu durumda daha iyidir sapply(veya vektörelleştirme) ve devrik.
mbq

1
@mbq Tam olarak ne yapıyorum. Ayrıca, onu df <-data.frame () ile başlatırsanız, bir veri çerçevesi çıktısı verdiğini buldum.
Olga

9

Bu, [ile benzer olan ] do.call(rbind,)çıktısında nasıl kullanılacağına dair aptalca bir örnektir.Map()lapply()

> DF <- do.call(rbind,Map(function(x) data.frame(a=x,b=x+1),x=1:3))
> DF
  x y
1 1 2
2 2 3
3 3 4
> class(DF)
[1] "data.frame"

Bu yapıyı oldukça sık kullanıyorum.


8

Rcpp'den bu kadar hoşlanmamın sebebi, R Core'un nasıl düşündüğünü her zaman anlayamamam ve Rcpp ile çoğu zaman buna mecbur kalmamam.

Felsefi olarak konuşursak, her değerin diğer her değerden bağımsız görünmesini sağlamaya çalışan işlevsel paradigma konusunda günah durumundasınız ; Bir değeri değiştirmek, C'deki temsili paylaşan işaretçilerle elde ettiğiniz gibi, başka bir değerde hiçbir zaman gözle görülür bir değişikliğe neden olmamalıdır.

Fonksiyonel programlama küçük geminin yoldan çekilmesini işaret ettiğinde ve küçük araç "Ben bir deniz feneriyim" diye yanıt verdiğinde sorunlar ortaya çıkar. Bu arada işlemek istediğiniz büyük bir nesnede uzun bir dizi küçük değişiklik yapmak, sizi deniz fenerinin bölgesine yerleştirir.

C ++ STL'de push_back()bir yaşam tarzıdır. İşlevsel olmaya çalışmaz, ancak yaygın programlama deyimlerini verimli bir şekilde barındırmaya çalışır .

Perde arkasındaki biraz zekayla, bazen her dünyada bir ayağınızın olmasını ayarlayabilirsiniz. Anlık görüntü tabanlı dosya sistemleri iyi bir örnektir (her iki tarafı da katlayan birleşim ayakları gibi kavramlardan gelişmiştir).

R Core bunu yapmak isterse, temeldeki vektör depolaması birleşim montajı gibi işlev görebilir. Vektör depolamaya 1:Nbir referans, aboneler için geçerli olabilirken , aynı depolamaya başka bir referans, aboneler için geçerlidir 1:(N+1). Henüz herhangi bir şey tarafından geçerli bir şekilde referans gösterilmeyen ancak hızlı bir şekilde uygun olan ayrılmış depolama alanı olabilir push_back(). Mevcut herhangi bir referansın geçerli olduğunu düşündüğü aralığın dışına ekleme yaparken işlevsel kavramı ihlal etmezsiniz.

Sonunda artımlı olarak satırlar eklediğinizde, ayrılmış depolama alanınız tükenir. Her şeyin yeni kopyalarını, depolama alanı bir miktar artışla çarpılarak oluşturmanız gerekir. Kullandığım STL uygulamaları, ayırmayı genişletirken depolamayı 2 ile çarpma eğilimindedir. R Internals'da depolamanın% 20 arttığı bir bellek yapısı olduğunu okuduğumu sanıyordum. Her iki durumda da büyüme işlemleri, eklenen toplam eleman sayısına göre logaritmik frekansla gerçekleşir. İtfa esasına göre, bu genellikle kabul edilebilir.

Perde arkasındaki hileler gittikçe daha kötülerini gördüm. push_back()Veri çerçevesine her yeni satır girdiğinizde, üst düzey bir dizin yapısının kopyalanması gerekir. Yeni satır, herhangi bir eski işlevsel değeri etkilemeden paylaşılan gösterime eklenebilir. Çöp toplayıcıyı fazla karmaşıklaştıracağını bile düşünmüyorum; Ben öneren değilim çünkü push_front()tüm referanslar tahsis vektör depolama önüne önek referanslar vardır.


2

Dirk Eddelbuettel'in cevabı en iyisidir; Burada, veri çerçevesi boyutlarını veya veri türlerini önceden belirlemekten kurtulabileceğinizi not ediyorum; bu, bazen birden çok veri türünüz ve çok sayıda sütununuz varsa yararlıdır:

row1<-list("a",1,FALSE) #use 'list', not 'c' or 'cbind'!
row2<-list("b",2,TRUE)  

df<-data.frame(row1,stringsAsFactors = F) #first row
df<-rbind(df,row2) #now this works as you'd expect.

Şunu mu demek istediniz df<-rbind(df, row2)?
Timothy C. Quinn

1

Matris olmadan ham veri çerçevesi oluşturmanın bu yolunu buldum.

Otomatik sütun adıyla

df<-data.frame(
        t(data.frame(c(1,"a",100),c(2,"b",200),c(3,"c",300)))
        ,row.names = NULL,stringsAsFactors = FALSE
    )

Sütun adıyla

df<-setNames(
        data.frame(
            t(data.frame(c(1,"a",100),c(2,"b",200),c(3,"c",300)))
            ,row.names = NULL,stringsAsFactors = FALSE
        ), 
        c("col1","col2","col3")
    )

0

Satır olacak vektörleriniz varsa, bunları kullanarak birleştirin c(), satır satır bir matrise aktarın ve bu matrisi bir veri çerçevesine dönüştürün.

Örneğin, satırlar

dummydata1=c(2002,10,1,12.00,101,426340.0,4411238.0,3598.0,0.92,57.77,4.80,238.29,-9.9)
dummydata2=c(2002,10,2,12.00,101,426340.0,4411238.0,3598.0,-3.02,78.77,-9999.00,-99.0,-9.9)
dummydata3=c(2002,10,8,12.00,101,426340.0,4411238.0,3598.0,-5.02,88.77,-9999.00,-99.0,-9.9)

bir veri çerçevesine dönüştürülebilir, böylece:

dummyset=c(dummydata1,dummydata2,dummydata3)
col.len=length(dummydata1)
dummytable=data.frame(matrix(data=dummyset,ncol=col.len,byrow=TRUE))

Kuşkusuz, 2 büyük sınırlama görüyorum: (1) bu yalnızca tek modlu verilerle çalışır ve (2) bunun çalışması için son # sütununuzu bilmeniz gerekir (yani, bir ile çalışmadığınızı varsayıyorum. en büyük satır uzunluğu önceden bilinmeyen düzensiz dizi ).

Bu çözüm basit görünüyor, ancak R'deki tür dönüştürmeleriyle ilgili deneyimlerime göre, yeni zorluklar yarattığına eminim. Bu konuda yorum yapan var mı?


0

Yeni satırınızın biçimine bağlı olarak, tibble::add_rowyeni satırınız basitse ve "değer çiftlerinde" belirtilebiliyorsa kullanabilirsiniz. Ya da dplyr::bind_rows"do.call (rbind, dfs) ​​ortak örüntüsünün verimli bir uygulaması" kullanabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.