Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion R/formulas.R
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ prb <- function(assessed, sale_price, na.rm = FALSE) {
# Calculate the Gini cofficients needed for KI and MKI
calc_gini <- function(assessed, sale_price) {
df <- data.frame(av = assessed, sp = sale_price)
df <- df[order(df$sp), ]
df <- df[order(df$sp, -df$av), ]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion, optional] I think we should add the same comment here as assesspy, to make sure it's clear in both places:

Suggested change
df <- df[order(df$sp, -df$av), ]
# This Gini coefficient algorithm is sensitive to the order of the input
# observations: If multiple observations share the same sale price but have
# different estimates, the output coefficients will be different depending
# on which of the sales with identical prices gets ordered first in the
# input dataframe. To ensure a stable sort order, Quintos recommends
# sorting by ascending sale price and then by descending estimate to break
# any ties. This produces "worst case" MKI/KI statistics, but ensures those
# statistics are deterministic. See this issue for more discussion:
# https://github.com/ccao-data/assesspy/issues/33#issuecomment-3180632954
df <- df[order(df$sp, -df$av), ]

assessed_price <- df$av
sale_price <- df$sp
n <- length(assessed_price)
Expand Down
31 changes: 31 additions & 0 deletions tests/testthat/data/mki_ki_data_with_tiebreaks.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"Sale_Price","Assessed","Assessed_alt_sort_1","Assessed_alt_sort_2"
32900,37299.37125,37299.37125,37299.37125
36000,40165.89269,40165.89269,40165.89269
54000,56317.4201,56317.4201,56317.4201
64500,66183.77244,66183.77244,66183.77244
68000,69486.97316,69486.97316,69486.97316
70000,71514.52586,71514.52586,71514.52586
74000,75338.28603,75338.28603,75338.28603
80000,81035.95111,81035.95111,81035.95111
84900,85672.85577,85672.85577,85672.85577
89000,85021.0865,94088.93683,90046.33945
89000,90046.33945,85021.0865,94088.93683
89000,94088.93683,90046.33945,85021.0865
105900,100227.0936,100227.0936,100227.0936
109000,103156.7516,103156.7516,103156.7516
115000,108290.1277,108290.1277,108290.1277
124500,117098.7563,117098.7563,117098.7563
129900,115346.9796,115346.9796,115346.9796
135000,119678.4223,119678.4223,119678.4223
149000,131630.9478,131630.9478,131630.9478
155800,137321.2061,137321.2061,137321.2061
163500,143973.5639,143973.5639,143973.5639
175000,153571.8563,153571.8563,153571.8563
179000,148456.8866,148456.8866,148456.8866
185600,153488.3876,153488.3876,153488.3876
199900,165039.8271,165039.8271,165039.8271
215000,176939.5763,176939.5763,176939.5763
235000,192959.3127,192959.3127,192959.3127
250000,180046.1193,180046.1193,180046.1193
279000,200240.2442,200240.2442,200240.2442
295000,211445.4891,211445.4891,211445.4891
43 changes: 43 additions & 0 deletions tests/testthat/test-formulas.R
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ mki_ki_data <- read.csv(
mki_ki_assessed <- mki_ki_data$Assessed
mki_ki_sale_price <- mki_ki_data$Sale_Price

mki_tiebreaks <- read.csv(
rprojroot::find_testthat_root_file("data/mki_ki_data_with_tiebreaks.csv")
)

tiebreaks_Sale_Price <- mki_tiebreaks$Sale_Price
tiebreaks_Assessed <- mki_tiebreaks$Assessed
tiebreaks_Assessed_alt_sort_1 <- mki_tiebreaks$Assessed_alt_sort_1
tiebreaks_Assessed_alt_sort_2 <- mki_tiebreaks$Assessed_alt_sort_2



##### TEST COD #####
Expand Down Expand Up @@ -184,6 +193,22 @@ test_that("standard met function", {
expect_false(mki_met(mki_out))
})

test_that("all sorting variations return the same MKI (tiebreak data)", {
mki_out_assessed <- mki(
tiebreaks_Assessed, tiebreaks_Sale_Price
)
mki_out_assessed_alt_sort1 <- mki(
tiebreaks_Assessed_alt_sort_1,
tiebreaks_Sale_Price
)
mki_out_assessed_alt_sort2 <- mki(
tiebreaks_Assessed_alt_sort_2,
tiebreaks_Sale_Price
)

expect_equal(mki_out_assessed, mki_out_assessed_alt_sort1)
expect_equal(mki_out_assessed, mki_out_assessed_alt_sort2)
})


##### TEST KI #####
Expand Down Expand Up @@ -224,6 +249,24 @@ test_that("incomplete data returns NAs unless removed", {
)
})

test_that("all sorting variations return return the same ki (tiebreak data)", {
ki_out_assessed <- ki(
tiebreaks_Assessed,
tiebreaks_Sale_Price
)
ki_out_assessed_alt_sort1 <- ki(
tiebreaks_Assessed_alt_sort_1,
tiebreaks_Sale_Price
)
ki_out_assessed_alt_sort2 <- ki(
tiebreaks_Assessed_alt_sort_2,
tiebreaks_Sale_Price
)

expect_equal(ki_out_assessed, ki_out_assessed_alt_sort1)
expect_equal(ki_out_assessed, ki_out_assessed_alt_sort2)
})


##### TEST Median Ratio #####
context("test median_ratio_met function")
Expand Down
Loading