Come faccio a costruire una colonna A, le cui voci sono uguali alla media/mediana/modalità delle ultime 10 voci non nulle di un'altra colonna B?Ciao,
Ho una colonna A (circa 15.000 righe) che ha numeri e molti valori nulli (forse 70-80% null).
Vorrei costruire una colonna B che alla riga i, è uguale alla media di: gli *ultimi 10 valori non nulli da A*
--> questo significa prendere A[row i-1] , A[row i-2], ... e tornare indietro fino a quando non hai 10 valori non nulli (o se raggiungi la riga 1, prendi qualsiasi numero <= 10 di valori non nulli che ottieni)
Vorrei anche fare oltre a significare, una mediana e anche una modalità, ma una versione smussata della modalità in cui:
Per prima cosa eseguo un livellamento gaussiano dei 10 valori non nulli ... e prendo argmax (modalità) di quelle distribuzioni.
Grazie per qualsiasi pensiero o suggerimento!
***
Idee per la soluzione: un pensiero che avevo era perché voglio eseguire diversi calcoli con gli ultimi 10 valori non nulli, dovrei prima costruire una colonna C le cui voci sono matrici uguali a quegli ultimi 10 valori non nulli ... quindi io può fare 3 formule che operano sulla colonna C per produrre B1 (media), B2 (mediale), B3 (modalità livellata).
Ecco alcuni frammenti di codice che si muovono verso la costruzione di questa colonna C di array:
//step 1 grab the last say 50 entries (some fixed amount that will likely have 10 non-nulls)
For Each Row( dt_join,
to = Row();
If( to - 50 < 0,
from = 1,
from = to - 50); // Quantile( 0.5,
values = :away_1g_pull_seconds[Index( From, To )] < 50, Break());
);
//step 2 convert array to list, drop nulls, convert list of first 10 entries back to array ...
//I don't know how to assign this to a row of C
num_lag = 10;
values = dt_join:A[Index( From, To )] ;
MyList = Remove(as list(values)[1], as list(Loc(as list(values)[1], .)) ); //convert array to list and remove nulls
Mat = Number Col Box("", MyList[1:10]) << get as matrix; //hack convert to array
Tabella datiSceneggiaturaRi: Come posso costruire una colonna A, le cui voci sono uguali alla media/mediana/modalità delle ultime 10 voci non nulle di un'altra colonna B?Ecco un inizio per la tua prima richiesta.Creerà una media per gli ultimi 10 valori per la colonna A e inserirà la media nella colonna B
Non ho tempo in questo momento per lavorare di più su questo.Forse più tardi questo fine settimana.
Names Default To Here( 1 );
dt = Current Data Table();
theMatrix = [];
dt << New Column( "B" );
For Each Row(
If( Is Missing( :A ) == 0,
theMatrix = Matrix( :a ) || theMatrix
);
If( Length( theMatrix ) > 10,
theMatrix[1, 11] = []
);
:B = Mean( theMatrix );
);
Ri: Come posso costruire una colonna A, le cui voci sono uguali alla media/mediana/modalità delle ultime 10 voci non nulle di un'altra colonna B?@DonMcCormack questo sarebbe un buon problema di sfida.
Penso che funzionerà e sarà ragionevolmente efficiente.
nr = 15000;
dt = New Table( "Untitled",
Add Rows( nr ),
New Column( "a", Numeric, "Continuous", Format( "Best", 12 ), Set Values( J( nr, 1, If( Random Uniform() < .3, Random Integer( 0, 1 ), . ) ) ) )
);
lookback = 10;
dt << New Column( "b" || Char( lookback ),
formula(
// make a helper to help look up the non-missing rows
helper = As Constant( // AsConstant is for efficiency
temp = dt << getrowswhere( !Is Missing( a ) );
// temp is the non-missing row numbers. Make sure row 1
// is included, even if missing, because LocSorted will
// return [1] when a smaller value would have been better.
If( temp[1] != 1,
Insert Into( temp, 1, 1 )
);
temp; // this is assigned to 'helper'
);
currentrow = Row(); // this is the target for a new mean, etc
end = Loc Sorted( helper, currentrow )[1]; // end is the last non missing row before or at the target
start = Max( 1, end - lookback + 1 ); // start is the row 'lookback' rows earlier
rowset = helper[start :: end]; // rowset is the set of nonmissing rows, possibly including a missing value at row 1.
// it is OK if a missing value is present; mean/median/mode ignore it.
// grab the rowset from column a and report the statistic...
Mean( dt[rowset, {a}] );// median, mode
)
);
Ri: Come posso costruire una colonna A, le cui voci sono uguali alla media/mediana/modalità delle ultime 10 voci non nulle di un'altra colonna B?Ciao,
Ecco un altro modo per farlo, utilizzando una tabella intermedia senza mancanze, che consente una formula più semplice.
Names Default To Here( 1 );
dt = Current Data Table();
//get nonmissing rows of table and put them in a new table
m = dt << get rows where( !Is Missing( :a ) );
dt2 = New Table( "xxx", invisible, <<ADD rows=""></ADD>
Quando la tabella originale è piccola (come la tua... circa 15.000 righe), i due approcci si comportano in modo simile: il primo è un po' più veloce:

Man mano che la tabella originale cresce, l'approccio "tabella separata" si ridimensiona in modo sensibilmente migliore, correndo in circa 1/10 del tempo. Ecco un esempio di riga 150K:

Un possibile problema (??) è che questo approccio non produce una formula nella tabella di origine, quindi è necessario rieseguirlo ogni volta che vengono aggiunti nuovi dati.
Ho allegato il file di riga 150K nel caso in cui desideri sperimentare.
Saluti,
Brady
Ri: Come posso costruire una colonna A, le cui voci sono uguali alla media/mediana/modalità delle ultime 10 voci non nulle di un'altra colonna B?Ecco altri risultati. Il metodo "separato" sembra ridimensionarsi in modo lineare. Il metodo della "stessa tabella" sembra colpire un muro da qualche parte a nord di 450.000 righe. Non sono sicuro del perché.


Ri: Come posso costruire una colonna A, le cui voci sono uguali alla media/mediana/modalità delle ultime 10 voci non nulle di un'altra colonna B?Immagino che sia ancora N^2 per l'helper=AsConstant. Questo copierà un array da 100.000 400.000 volte...
modifica: supposizione confermata. Ma anche rimuovere l'helper dalla formula lascia il mio codice circa la metà più veloce di quello di Brady.
Ma... il codice di Jim può essere modificato per essere più veloce...
dt = Current Data Table();
startTime = Tick Seconds();
theMatrix = {., ., ., ., ., ., ., ., ., .};
z = .;
dt << New Column( "B" );
dt << begindataupdate;
For Each Row(
v = :A;
If( v == v,
Insert Into( theMatrix, v );
Remove From( theMatrix, 1 );
z = Mean( theMatrix );
);
:B = z;
);
stopTime = Tick Seconds();
Show( stopTime - startTime );
dt << enddataupdate;Ri: Come posso costruire una colonna A, le cui voci sono uguali alla media/mediana/modalità delle ultime 10 voci non nulle di un'altra colonna B?Grazie mille per tutte le vostre risposte - sono sbalordito!
Non ho avuto modo di leggerli in dettaglio ma risponderò di più quando lo farò.
Migliore,
Gio
Ri: Come posso costruire una colonna A, le cui voci sono uguali alla media/mediana/modalità delle ultime 10 voci non nulle di un'altra colonna B?È davvero bello, molto più elegante del mio approccio.
Ri: Come posso costruire una colonna A, le cui voci sono uguali alla media/mediana/modalità delle ultime 10 voci non nulle di un'altra colonna B?Wow......questo esercizio mi ha insegnato qualcosa.Il mio codice originale funzionava, ma era molto più lento dei metodi alternativi, che mi sono preso il tempo per studiarli.Codice molto veloce e intelligente.Quindi @Craige_Hales ha fornito il suo ultimo codice, che è abbastanza veloce, ma ha un approccio molto vicino a quello che il mio codice originale ha in approccio.@Craige_Hales il codice è molto più veloce.E la maggior parte della differenza sta nella mia mancanza di utilizzo
Begin Data Update;
.....
End Data Update;
Quindi ora ho ottenuto un grande apprezzamento per la sospensione dei messaggi di aggiornamento fino alla fine dell'aggiornamento.
Grazie per il divertimento!