¿Cómo construyo una columna A, cuyas entradas son iguales a la media/mediana/moda de las últimas 10 entradas no nulas de otra columna B?Hola,
Tengo una columna A (alrededor de 15,000 filas) que tiene números y muchos valores nulos (quizás 70-80% nulo).
Me gustaría construir una columna B que en la fila i sea igual a la media de: los *últimos 10 valores no nulos de A*
--> esto significa tomar A[row i-1] , A[row i-2], ... y retroceder hasta que tenga 10 valores no nulos (o si llega a la fila 1, tome cualquier número <= 10 de valores no nulos que obtienes)
También me gustaría hacer además de la media, una mediana y también una moda, pero una versión suavizada de la moda donde:
Primero hago un suavizado gaussiano de los 10 valores no nulos... y tomo el argmax (modo) de esas distribuciones.
¡Gracias por cualquier idea o sugerencia!
***
Ideas de solución: un pensamiento que tuve fue porque quiero hacer varios cálculos diferentes con los últimos 10 valores no nulos, primero debería construir una columna C cuyas entradas sean matrices iguales a esos últimos 10 valores no nulos ... luego puede hacer 3 fórmulas que operan en la columna C para producir B1 (media), B2 (medial), B3 (modo suavizado).
Aquí hay algunos fragmentos de código que avanzan hacia la construcción de esta columna C de matrices:
//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
Tabla de datossecuencias de comandosRe: ¿Cómo construyo una columna A, cuyas entradas son iguales a la media/mediana/moda de las últimas 10 entradas no nulas de otra columna B?Aquí hay un comienzo para su primera solicitud.Creará una media para los últimos 10 valores de la columna A y colocará la media en la columna B
No tengo tiempo ahora mismo para trabajar más en esto.Tal vez más tarde este fin de semana.
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 );
);
Re: ¿Cómo construyo una columna A, cuyas entradas son iguales a la media/mediana/moda de las últimas 10 entradas no nulas de otra columna B?@DonMcCormack esto sería un buen problema de desafío.
Creo que esto funcionará y será razonablemente eficiente.
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
)
);
Re: ¿Cómo construyo una columna A, cuyas entradas son iguales a la media/mediana/moda de las últimas 10 entradas no nulas de otra columna B?Hola,
Aquí hay otra forma de hacer esto, usando una tabla intermedia sin faltantes, lo que permite una fórmula más simple.
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>
Cuando la tabla original es pequeña (como la suya... alrededor de 15 000 filas), los dos enfoques funcionan de manera similar: el primero es un poco más rápido:

A medida que crece la tabla original, las escalas de enfoque de "tabla separada" parecen escalar considerablemente mejor, ejecutándose en aproximadamente 1/10 del tiempo. Aquí hay un ejemplo de fila de 150K:

Un posible factor decisivo (??) es que este enfoque no produce una fórmula en la tabla de origen, por lo que deberá volver a ejecutar esto cada vez que se agreguen nuevos datos.
Adjunté el archivo de fila de 150K en caso de que quieras experimentar.
Salud,
Brady
Re: ¿Cómo construyo una columna A, cuyas entradas son iguales a la media/mediana/moda de las últimas 10 entradas no nulas de otra columna B?Aquí hay algunos resultados más. El método "separado" parece escalar linealmente. El método de la "misma tabla" parece chocar con una pared en algún lugar al norte de las 450 000 filas. No estoy seguro de por qué.


Re: ¿Cómo construyo una columna A, cuyas entradas son iguales a la media/mediana/moda de las últimas 10 entradas no nulas de otra columna B?Supongo que todavía es N^2 para helper=AsConstant. Eso será copiar una matriz de 100K 400K veces...
editar: conjetura confirmada. Pero incluso sacar al ayudante de la fórmula deja mi código aproximadamente la mitad de rápido que el de Brady.
Pero... el código de Jim se puede modificar para que sea más rápido...
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;Re: ¿Cómo construyo una columna A, cuyas entradas son iguales a la media/mediana/moda de las últimas 10 entradas no nulas de otra columna B?¡Muchas gracias por todas sus respuestas, estoy impresionado!
No he tenido la oportunidad de leerlos en detalle, pero responderé más cuando lo haga.
Mejor,
José
Re: ¿Cómo construyo una columna A, cuyas entradas son iguales a la media/mediana/moda de las últimas 10 entradas no nulas de otra columna B?Eso es realmente bueno, mucho más elegante que mi enfoque.
Re: ¿Cómo construyo una columna A, cuyas entradas son iguales a la media/mediana/moda de las últimas 10 entradas no nulas de otra columna B?Vaya... este ejercicio me enseñó un montón.Mi código original funcionó, pero era mucho más lento que los métodos alternativos, por lo que me tomé el tiempo para estudiarlos.Código muy rápido e inteligente.Después @Craige_Hales proporcionó su último código, que es muy rápido, pero adopta un enfoque muy cercano al enfoque de mi código original.@Craige_Hales el código es mucho más rápido.Y la mayor parte de la diferencia está en mi falta de uso
Begin Data Update;
.....
End Data Update;
Así que ahora he obtenido un gran aprecio por la demora de los mensajes de actualización hasta el final de la actualización.
¡Gracias por la diversión!