Select to view content in your preferred language

Arcade fonction for calculate Median

1731
7
Jump to solution
05-26-2022 10:01 AM
User1RECS
Emerging Contributor

HI All,

can you please tell me how to calculate the Median Value of a liste in Arcade. there is not a fonction for calculate the median Value

0 Kudos
1 Solution

Accepted Solutions
JohannesLindner
MVP Alum

Well, you just take Josh's answer and apply it to your table:

// load the whole feature class
var fs_buildings = FeatureSetByName($datastore, "BuildingFC", ["BlockID", "BuildingID", "BuildingHeight", "BuildingArea"], false)

// only select rows with the current feature's BlockID
var id = $feature.BlockID
var fs_buildings_block = Filter(fs_buildings, "BlockID = @ID")

// define a median function
function median(values) {
    var c = Count(values)
    var ordered = Sort(values)
    Console('Odd number of items. Returning central item')
    if(c%2 == 1) {
        return ordered[((c+1)/2)-1]
    }
    var a = ordered[(c/2)-1]
    var b = ordered[(c/2)]
    return (a+b)/2
}

// get your values
var values = []
for(var f in fs_buildings_block) {
    Push(values, f.BuildingHeight)
}

// calculate and return the median
return median(values)

Have a great day!
Johannes

View solution in original post

7 Replies
jcarlson
MVP Esteemed Contributor

It does seem a bit of a limitation, but we can make up our own function.

We know that with an odd number of items of length n, the median is the item in position (n+1)/2.

Even numbers get a bit trickier, since we want a number halfway between the central two numbers. That is, ((n/2) + ((n+1)/2) / 2)

So what does this look like in Arcade?

First, we need to know if it's even or odd. That's easy enough, just use Count against your list and modulo divide by 2.

Second, we need to Sort the list. When using the Sort function without specifying a custom function will default to ordering your list items in ascending order.

Once sorted, we use one of the two formulas above depending on even or odd, then we return the value.

Final note: list indexes are 0-based, so we have to actually decrement the index we're returning.

Here's what it might look like with a sample input.

// Create a function to check even or odd
function isOdd(value){
    return Boolean(value % 2);
}

// Create an array, populate it with random numbers from 1-100
var some_list = [];

for (var x = 0; x < 100; x++){
    Push(some_list, Random()*100)    
}

// Sort list
var ordered = Sort(some_list)

// Get count of items
var c = Count(ordered)

// Check if even or odd return appropriate value
if (isOdd(c)){
    Console('Odd number of items. Returning central item')
    return ordered[((c+1)/2)-1]
} else {
    Console('Even number of items. Averaging central two')
    var a = ordered[(c/2)-1]
    var b = ordered[(c/2)]
    return (a+b)/2
}

 

Just to see that it works, here are the outputs with known "correct" values.

jcarlson_0-1653589902932.pngjcarlson_1-1653589918306.png

 

- Josh Carlson
Kendall County GIS
User1RECS
Emerging Contributor

Thank you so much for your response. i have a table with buildings by blocks and each building has its area and height. could you,please, give me the expression to calculate the median area for each block in a new field?

0 Kudos
JohannesLindner
MVP Alum

Well, you just take Josh's answer and apply it to your table:

// load the whole feature class
var fs_buildings = FeatureSetByName($datastore, "BuildingFC", ["BlockID", "BuildingID", "BuildingHeight", "BuildingArea"], false)

// only select rows with the current feature's BlockID
var id = $feature.BlockID
var fs_buildings_block = Filter(fs_buildings, "BlockID = @ID")

// define a median function
function median(values) {
    var c = Count(values)
    var ordered = Sort(values)
    Console('Odd number of items. Returning central item')
    if(c%2 == 1) {
        return ordered[((c+1)/2)-1]
    }
    var a = ordered[(c/2)-1]
    var b = ordered[(c/2)]
    return (a+b)/2
}

// get your values
var values = []
for(var f in fs_buildings_block) {
    Push(values, f.BuildingHeight)
}

// calculate and return the median
return median(values)

Have a great day!
Johannes
User1RECS
Emerging Contributor

It work perfectly. Thank you very much !!!!!

0 Kudos
User1RECS
Emerging Contributor

Help me, Please

0 Kudos
JohannesLindner
MVP Alum

Dude, relax. We all have our own jobs to take care of before helping others here...


Have a great day!
Johannes
0 Kudos
ZachBodenner
MVP Regular Contributor

Reviving an old threat here, but I wanted to throw some thanks at @JohannesLindner and @jcarlson . I used and modified your Median function to also find quartiles for calculating outliers of a dataset and I wanted to share it in case anyone else might find it useful. Very neat, thanks for this!

// Get list of sales as a featureset
var sales = featuresetbyname($datastore,'epgdb.assessing.VAS_Sales')

// Count them
var countOfSales = count(sales)
console (countOfSales)

// The attribute that we will use to run the calculations on
var r = $feature.Direct_Sales_Ratio

// define a median function
function median(values) {
    var c = Count(values)
    var ordered = Sort(values)
    if(c%2 == 1) {
        return ordered[((c+1)/2)-1]
    }
    var a = ordered[(c/2)-1]
    var b = ordered[(c/2)]
    return (a+b)/2
}


//define q1 function. Instead of diving by 2 to fine median, multiple by 1/4 to get first quartile.
function quart1(values) {
    var c = Count(values)
    var ordered = Sort(values)
    if(c%2 == 1) {
        return ordered[((c+1)*.25)-1]
    }
    var a = ordered[(c*.25)-1]
    var b = ordered[(c*.25)]
    return (a+b)*.25
}

//define q3 function. Instead of diving by 2 to fine median, multiple by 3/4 to get third quartile.
function quart3(values) {
    var c = Count(values)
    var ordered = Sort(values)
    if(c%2 == 1) {
        return ordered[((c+1)*.75)-1]
    }
    var a = ordered[(c*.75)-1]
    var b = ordered[(c*.75)]
    return (a+b)*.75
}

// get your values
var values = []
for(var f in sales) {
    Push(values, f.Direct_Sales_Ratio)
}

// Establish values for calculation
var medianValue = median(values)
var q1 = quart1(values)
var q3 = quart3(values)
var IQR = q3-q1
var IQRt = IQR*1.5
var lowValue = q1-IQRt
var highValue = q3+IQRt
console("Median Value: "+medianValue)
console("Q1 Value: "+q1)
console("Q3 Value: "+q3)
console ("Interquartile Range (IQR): "+IQR)
console ("1.5 times the IQR: "+IQRt)
console("Low Outlier Check: "+lowValue)
console("High Outlier Check: "+highValue)

// Value is an outlier if it is greater or less than 1.5*IQR 
if (r<lowValue){return "Low Outlier"}
else if (r>highValue){return "High Outlier"}
else {return "Not Outlier"}

 

Happy mapping,
- Zach
0 Kudos