openavmkit.utilities.sales_scrutiny
Multi-parcel ("bulk") deed detection helpers for sales scrutiny.
A bulk deed conveys several parcels for one consideration, and that one price usually gets
stamped onto every parcel's sales record. None of those per-parcel prices is a usable
arm's-length price, so the heuristics in run_heuristics
(:mod:openavmkit.sales_scrutiny_study) try to find them:
flag_dupe_deed_date-- rows sharing a deed (analysis.sales_scrutiny.deed_id) and sale date.flag_dupe_date_price-- rows sharing a sale date and sale price. This is the fallback for jurisdictions without usable deed IDs: identical date + price across parcels is the footprint a bulk deed leaves behind. When deed IDs are available it is narrowed so that unrelated sales on separate deeds that merely coincide on date and price are not flagged.flag_bulk_deed-- deeds that covered more than one parcel at ingestion (sale_parcel_count, computed in :func:openavmkit.data.process_databefore the valid-sale filter), which catches bulk deeds whose sibling rows were filtered out and so left nothing for (1) or (2) to match against.
This module only depends on pandas so that :mod:openavmkit.data can use it without a
circular import.
count_parcels_per_deed
count_parcels_per_deed(df, deed_id=None, jurisdiction=None)
Number of distinct parcels (key) on each row's deed, as nullable Int64.
NA where the deed is unknown. Returns None when deeds or parcel keys can't be identified.
Source code in openavmkit/utilities/sales_scrutiny.py
62 63 64 65 66 67 68 69 70 71 72 73 | |
deed_group_ids
deed_group_ids(df, deed_id=None, jurisdiction=None)
Identify the deed (transaction) each sales row belongs to.
With a configured deed_id column: [jurisdiction] + deed + sale_date, and NA for
rows whose deed is missing (unknown deeds must not group together). The jurisdiction is
only used when that column is present in df. Without a usable deed_id: the row's
key_sale. Returns None when neither is available.
Source code in openavmkit/utilities/sales_scrutiny.py
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | |
flag_bulk_deeds
flag_bulk_deeds(df)
Rows whose deed covered more than one parcel when the sales were loaded.
Uses sale_parcel_count from :func:openavmkit.data.process_data, which is counted
before invalid sales are filtered out. That catches an "orphan" bulk deed: one whose other
parcels' rows were dropped, so the duplicate-based heuristics have nothing left to match
against, but whose surviving row still carries the whole bundle's price. Without that
column, nothing is flagged.
Source code in openavmkit/utilities/sales_scrutiny.py
126 127 128 129 130 131 132 133 134 135 136 137 | |
flag_dupe_date_price
flag_dupe_date_price(df, jurisdiction=None, deed_id=None)
Rows that share their sale date and sale price with another row.
Without deed IDs, every row in a repeated (date, price) group is flagged: that pattern is the only trace a bulk deed leaves when you can't see the deed itself, and dropping a few coincidental matches is the price of catching them.
With deed IDs, a row in a repeated (date, price) group is flagged only if something suggests it's part of a bundle or a duplicate record:
- its deed is missing, or some other row in the group has a missing deed (which could be its sibling), or
- it shares its deed with another row in the group, or
- the same parcel appears more than once in the group.
So unrelated sales on separate, known deeds that happen to match on date and price (a round price, or a builder selling identical lots on separate deeds) are kept.
Source code in openavmkit/utilities/sales_scrutiny.py
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | |
flag_dupe_deed_date
flag_dupe_deed_date(df, deed_id, jurisdiction=None)
Rows that share their deed and sale date with another row.
Rows with a missing deed are never flagged here; they're left to flag_dupe_date_price.
Source code in openavmkit/utilities/sales_scrutiny.py
76 77 78 79 80 81 82 83 84 85 | |