Ho un set di dati con tre colonne X, Y e Z. Ci sono diverse righe nella tabella. Le coordinate X e Y in ogni riga sono una posizione nello spazio XY e Z è l'altezza in quella posizione XY. Voglio creare un cluster 3x3 in ogni posizione XY e calcolare la media di 8 punti vicini più vicini (escluso il punto centrale). Quindi sottrarre l'altezza Z della posizione XY al centro dalla media calcolata e se la differenza è maggiore della soglia (decisa dall'utente), quella posizione XY verrà chiamata outlier. Ciò continuerà fino a quando tutte le posizioni XY non saranno state verificate valore anomalo. Esistono funzioni integrate in JMP che posso utilizzare? Come posso scriverlo in JSL? Inoltre, come vengono gestite le coordinate del bordo? Di seguito è mostrata un'immagine di esempio. Qualsiasi guida sarà molto apprezzata.

un'idea simile, un'implementazione diversa
// make sample data
dt = New Table( "sample",
New Column( "x", Numeric, "Continuous", Format( "Best", 12 ) ),
New Column( "y", Numeric, "Continuous", Format( "Best", 12 ) ),
New Column( "z", Numeric, "Continuous", Format( "Best", 12 ) )
);
For( ix = 0, ix < 200, ix += 1,
For( iy = 0, iy < 250, iy += 1,
dt << addrows( 1 );
dt:x = ix;
dt:y = iy;
dt:z = Random Normal( 30, .25 );
)
);
// load into a matrix that is 1 row/col bigger all around
// this assumes the x/y data is gridded, integers, no holes
// but no particular order
xmin = Col Min( dt:x );
xmax = Col Max( dt:x );
ymin = Col Min( dt:y );
ymax = Col Max( dt:y );
m = J( ymax - ymin + 3, xmax - xmin + 3, . );// +3 makes a border of missing values on all sides
For( i = 1, i <= N Rows( dt ), i += 1,
// subtract minimum makes it zero based. add 1 to get one-based, but add 2 to leave the border
m[dt:y[i] - ymin + 2, dt:x[i] - xmin + 2] = dt:z[i]; // copy each z to its x,y (col,row) element
);
meanmat = J( ymax - ymin + 1, xmax - xmin + 1, . ); // +1 is original size
// the x and y loops do not include the border
For( ix = 2, ix <= N Cols( m ) - 1, ix += 1,
For( iy = 2, iy <= N Rows( m ) - 1, iy += 1,
// smallmat is 3x3 and may include missing values from border
smallmat = m[(iy - 1) :: (iy + 1), (ix - 1) :: (ix + 1)];
smallmat[2, 2] = .;// remove center point from consideration
meanmat[iy - 1, ix - 1] = Mean( smallmat ); // mean ignores missing values: mean([8 2 .])==5
)
);
threshold = .5; // detection threshold
// the error matrix has 0 for ok, 1 for beyond threshold. the subscripts on m[]
// remove the border to make it line up with the meanmat.
error = Abs( m[2 :: (ymax - ymin + 2), 2 :: (xmax - xmin + 2)] - meanmat ) > threshold;
// add the outlier indicator back to the table
dt << New Column( "outliers" );
For( i = 1, i <= N Rows( dt ), i += 1,
dt:outliers[i] = error[dt:y[i] - ymin + 1, dt:x[i] - xmin + 1]
);
// fiddle with the tabl's row states to make the graph
dt << colorOrMarkByColumn( outliers );
dt << selectwhere( outliers == 1 );
// a graph
dt << Surface Plot(
Columns( :x, :y, :z ),
Datapoints Choice( "Points" ),
Response( :z ),
Surface Color Method( "Solid", "Solid", "Solid", "Solid" ),
SetVariableAxis( :x, Axis Data( {} ) ),
SetVariableAxis( :y, Axis Data( {} ) ),
SetZAxis( :z, Current Value( 30.5 ) ),
SetXVariable( :x ),
SetYVariable( :y ),
Frame3D(
Set Graph Size( 900, 900 ),
Set Rotation( -89, 1, -35 )
)
);
Red outliers above and below blue cloudRed outliers above and below blue cloudValori anomali rossi sopra e sotto la nuvola blu
Ciò presuppone che le coordinate x e y dei dati siano numeri interi consecutivi. Assicurati che il comportamento del bordo sia quello che ti aspetti e assicurati che il centro sia lasciato fuori come ti aspetti. Prova attentamente! Ad esempio, un caso 2x2 come questo:
Tiny test case making use of the missing value border, a lot!Tiny test case making use of the missing value border, a lot!Piccolo caso di test che utilizza molto il bordo del valore mancante!
Non ci sono funzioni che possono essere richiamate per questo processo di dati molto specializzato. Ecco un breve script che esegue il compito essenziale.
Names Default to Here( 1 );
dt1 = Current Data Table();
// dimensions of results
nr = Col Maximum( dt1:Y ) - 1; // assumes first level is 0
nc = Col Maximum( dt1:X ) - 1; // assumes first level is 0
net height = [];
// iterate over 3x3 cells
For( c = 1, c < nc, c++,
For( r = 1, r < nr, r++,
cell = dt1 << Get Rows Where(
Or(
:X == r-1 & :Y == c-1,
:X == r-1 & :Y == c,
:X == r-1 & :Y == c+1,
:X == r & :Y == c-1,
:X == r & :Y == c,
:X == r & :Y == c+1,
:X == r+1 & :Y == c-1,
:X == r+1 & :Y == c,
:X == r+1 & :Y == c+1,
)
);
target = dt1 << Get Rows Where( :X == r & :Y == c );
net height |/= Matrix( { c, r, (((Sum( dt1:Z[cell] ) - dt1:Z[target]) / 8)</img> - dt1:z[target])[1] } )`;
);
);
dt2 = As Table( net height, << Column Names( { "X", "Y", "Net Z" } ) );
// assume user threshold is 1.5
threshold = 1.5;
dt2 << New Table Variable( "Threshold", "1.5" );
dt2 << New Column( "Outlier", "Numeric", "Nominal",
Values( net height[0,3] > threshold ),
Value Labels( {0 = "No", 1 = "Yes"} ),
Use Value Labels( 1 )
);
dt2 << New Script( "Plot Outliers",
Current Data Table() << Graph Builder(
Size( 522, 454 ),
Show Control Panel( 0 ),
Variables( X( :X ), Y( :Y ), Color( :Outlier ) ),
Elements( Points( X, Y, Legend( 3 ) ) )
);
);