我有一個包含三列 X、Y 和 Z 的資料集。 表中有幾行。 每行中的 X 和 Y 座標是 XY 空間中的一個位置,Z 是該 XY 位置的高度。 我想在每個 XY 位置建立一個 3x3 簇,並計算 8 個最近鄰點(不包括中心點)的平均值。 然後從計算的平均值中減去中心 XY 位置的 Z 高度,如果差值大於閾值(由使用者決定),則該 XY 位置將被稱為異常值。這將繼續,直到檢查完所有 XY 位置為止異常值。 JMP 中有我可以使用的內建函數嗎? 我如何在 JSL 中編寫它? 另外邊緣座標是如何處理的? 範例圖像如下所示。 任何指導都將受到高度讚賞。

相似的想法,不同的實現
// 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 cloud藍雲上方和下方的紅色異常值
這確實假設資料的 x 和 y 座標是連續整數。 確保邊緣行為符合您的預期,並確保中心按照您預期的方式被排除。 仔細測試一下! 例如,像這樣的 2x2 情況:
Tiny test case making use of the missing value border, a lot!Tiny test case making use of the missing value border, a lot!很多利用缺失值邊界的小測試用例!
沒有可以為這個非常專業的資料處理呼叫的函數。 這是執行基本任務的簡短腳本。
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 ) ) )
);
);