list - statistica - funzioni in r




Creazione di un dataframe R riga per riga (4)

Il motivo per cui mi piace così tanto Rcpp è che non sempre capisco come pensa R Core, e con Rcpp, il più delle volte, non ne ho bisogno.

Parlando filosoficamente, sei in uno stato di peccato rispetto al paradigma funzionale, che cerca di garantire che ogni valore appaia indipendente da ogni altro valore; la modifica di un valore non dovrebbe mai causare una modifica visibile in un altro valore, il modo in cui si ottiene con i puntatori che condividono la rappresentazione in C.

I problemi sorgono quando la programmazione funzionale segnala alla piccola imbarcazione di spostarsi e la piccola imbarcazione risponde "Sono un faro". Fare una lunga serie di piccole modifiche a un oggetto di grandi dimensioni che si desidera elaborare nel frattempo ti mette in quadrato nel territorio del faro.

Nel C ++ STL, push_back() è un modo di vivere. Non cerca di essere funzionale, ma cerca di accogliere gli idiomi di programmazione comuni in modo efficiente .

Con un po 'di intelligenza dietro le quinte, a volte puoi organizzare di avere un piede in ogni mondo. I file system basati su snapshot sono un buon esempio (che si è evoluto da concetti come union monts, che comprendono anche entrambi i lati).

Se R Core volesse fare ciò, lo storage vettoriale sottostante potrebbe funzionare come un union mount. Un riferimento alla memoria vettoriale potrebbe essere valido per gli indici 1:N , mentre un altro riferimento alla stessa memoria è valido per gli indici 1:(N+1) . Potrebbe esserci spazio di archiviazione riservato non ancora validamente referenziato da nulla ma comodo per un rapido push_back() . Non si viola il concetto funzionale quando si aggiunge al di fuori dell'intervallo che qualsiasi riferimento esistente considera valido.

Aggiungendo successivamente le righe in modo incrementale, si esaurisce lo spazio di archiviazione riservato. Avrai bisogno di creare nuove copie di tutto, con la memoria moltiplicata per qualche incremento. Le implementazioni STL che utilizzo tendono a moltiplicare lo spazio di archiviazione per 2 quando si estende l'allocazione. Ho pensato di leggere in R Internals che esiste una struttura di memoria in cui la memoria aumenta del 20%. In entrambi i casi, le operazioni di crescita si verificano con frequenza logaritmica rispetto al numero totale di elementi aggiunti. Su base ammortizzata, questo è generalmente accettabile.

Come trucchi dietro le quinte, ho visto di peggio. Ogni volta che push_back() una nuova riga sul dataframe, è necessario copiare una struttura di indice di livello superiore. La nuova riga potrebbe aggiungersi alla rappresentazione condivisa senza influire su alcun vecchio valore funzionale. Non penso nemmeno che complicherebbe molto il garbage collector; poiché non sto proponendo push_front() tutti i riferimenti sono prefissi al fronte della memoria vettoriale allocata.

Mi piacerebbe costruire un dataframe riga per riga in R. Ho fatto qualche ricerca, e tutto ciò che mi è venuto in mente è il suggerimento di creare una lista vuota, mantenere un indice scalare di lista, quindi ogni volta aggiungere all'elenco un dataframe a riga singola e far avanzare l'indice di lista di uno. Infine, do.call(rbind,) sulla lista.

Mentre funziona, sembra molto complicato. Non c'è un modo più semplice per raggiungere lo stesso obiettivo?

Ovviamente mi riferisco a casi in cui non posso usare alcune funzioni apply e ho esplicitamente bisogno di creare il dataframe riga per riga. Almeno, c'è un modo per inserire la fine di una lista invece di tenere esplicitamente traccia dell'ultimo indice utilizzato?


Puoi farli crescere riga per riga aggiungendo o usando rbind() .

Ciò non significa che dovresti. Le strutture a crescita dinamica sono uno dei modi meno efficienti per codificare in R.

Se puoi, basta conservare tutti i tuoi dati.frame in primo piano:

N <- 1e4  # some magic number, 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

e poi durante le operazioni inserisci riga alla volta

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

Questo dovrebbe funzionare per data.frame arbitrario ed essere molto più efficiente. Se hai superato N, puoi sempre ridurre le righe vuote alla fine.


Se si dispone di vettori destinati a diventare righe, concatenarli utilizzando c() , passarli a una matrice riga per riga e convertire tale matrice in un dataframe.

Ad esempio, righe

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)

può essere convertito in un frame di dati in questo modo:

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

Devo ammettere che ho 2 limitazioni principali: (1) funziona solo con dati in modalità singola e (2) devi conoscere le colonne # finali per far funzionare tutto questo (cioè, presumo che tu non stia lavorando con un array irregolare la cui lunghezza massima della fila è sconosciuta a priori ).

Questa soluzione sembra semplice, ma dalla mia esperienza con le conversioni di tipo in R, sono sicuro che crea nuove sfide down-the-line. Qualcuno può commentare questo?


Si possono aggiungere righe a NULL :

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

per esempio

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




dataframe