diff --git a/.idea/Model.iml b/.idea/Model.iml
index 4413bb06..b0f9c00d 100644
--- a/.idea/Model.iml
+++ b/.idea/Model.iml
@@ -7,7 +7,7 @@
-
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 6f308057..78660f34 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,7 +3,10 @@
-
+
+
+
+
diff --git a/etl/customers/stonewater/map_app/Stonewater Mapping Data.json b/etl/customers/stonewater/map_app/Stonewater Mapping Data.json
new file mode 100644
index 00000000..0d2978c4
--- /dev/null
+++ b/etl/customers/stonewater/map_app/Stonewater Mapping Data.json
@@ -0,0 +1 @@
+[{"uprn": 100050346525.0, "standardised_address": "32 VICTORIA ROAD, CROSS HILLS, KEIGHLEY", "standardised_postcode": "BD20 8SY", "LONGITUDE": -1.995112, "LATITUDE": 53.8997423}, {"uprn": 100050344995.0, "standardised_address": "20, Lang Kirk Close, Farnhill", "standardised_postcode": "BD20 9AR", "LONGITUDE": -1.9846986, "LATITUDE": 53.9106527}, {"uprn": 100050344996.0, "standardised_address": "22 LANG KIRK CLOSE, FARNHILL, KEIGHLEY", "standardised_postcode": "BD20 9AR", "LONGITUDE": -1.984729, "LATITUDE": 53.9107785}, {"uprn": 100050354230.0, "standardised_address": "34, Neville Road, Gargrave", "standardised_postcode": "BD23 3RE", "LONGITUDE": -2.1094417, "LATITUDE": 53.9833594}, {"uprn": 100050354235.0, "standardised_address": "39, NEVILLE ROAD, GARGRAVE, SKIPTON, BD23 3RE", "standardised_postcode": "BD23 3RE", "LONGITUDE": -2.1090613, "LATITUDE": 53.9836833}, {"uprn": 100071236000.0, "standardised_address": "3, Sorrell Place", "standardised_postcode": "CV10 7AY", "LONGITUDE": -1.4620998, "LATITUDE": 52.5044784}, {"uprn": 100030002639.0, "standardised_address": "6 St. Martins Court, Church Street, Amber Valley, DE55 7AH", "standardised_postcode": "DE55 7AH", "LONGITUDE": -1.3916142, "LATITUDE": 53.0973039}, {"uprn": 83008532.0, "standardised_address": "66, Belmont Terrace, Linthwaite", "standardised_postcode": "HD7 5SF", "LONGITUDE": -1.8505805, "LATITUDE": 53.6249856}, {"uprn": 83146613.0, "standardised_address": "35, Thorpes Crescent, Skelmanthorpe", "standardised_postcode": "HD8 9DH", "LONGITUDE": -1.6465264, "LATITUDE": 53.5871495}, {"uprn": 10010168062.0, "standardised_address": "2, HARVEST COURT, HALIFAX, HX1 5DU", "standardised_postcode": "HX1 5DU", "LONGITUDE": -1.869757, "LATITUDE": 53.722287}, {"uprn": 10006738671.0, "standardised_address": "6, DEAN COURT, HALIFAX, HX3 0UX", "standardised_postcode": "HX3 0UX", "LONGITUDE": -1.8767188, "LATITUDE": 53.6993657}, {"uprn": 100051314061.0, "standardised_address": "21, CHAPEL CLOSE, HOLYWELL GREEN, HALIFAX, HX4 9BF", "standardised_postcode": "HX4 9BF", "LONGITUDE": -1.8679148, "LATITUDE": 53.6762656}, {"uprn": 100051314049.0, "standardised_address": "2, Chapel Close, Holywell Green", "standardised_postcode": "HX4 9BF", "LONGITUDE": -1.8673862, "LATITUDE": 53.6758786}, {"uprn": 200002737104.0, "standardised_address": "35, Bradley View, Holywell Green", "standardised_postcode": "HX4 9DN", "LONGITUDE": -1.8707939, "LATITUDE": 53.675307}, {"uprn": 200001826125.0, "standardised_address": "56, BRADLEY VIEW, HOLYWELL GREEN, HALIFAX, HX4 9DN", "standardised_postcode": "HX4 9DN", "LONGITUDE": -1.871579, "LATITUDE": 53.675982}, {"uprn": 100052043238.0, "standardised_address": "50 Marton Heights, Hollins Lane", "standardised_postcode": "HX6 2RZ", "LONGITUDE": -1.9191337, "LATITUDE": 53.7123626}, {"uprn": 100052043248.0, "standardised_address": "6 Marton Heights, Hollins Lane", "standardised_postcode": "HX6 2RZ", "LONGITUDE": -1.9174519, "LATITUDE": 53.7124064}, {"uprn": 100052043251.0, "standardised_address": "8 Marton Heights, Hollins Lane", "standardised_postcode": "HX6 2RZ", "LONGITUDE": -1.9177397, "LATITUDE": 53.7124695}, {"uprn": 100052043217.0, "standardised_address": "31 Marton Heights, Hollins Lane", "standardised_postcode": "HX6 2RZ", "LONGITUDE": -1.9200123, "LATITUDE": 53.712489}, {"uprn": 10004000472.0, "standardised_address": "26, BENTLEY CLOSE, LOUGHBOROUGH, LE11 1SY", "standardised_postcode": "LE11 1SY", "LONGITUDE": -1.1965799, "LATITUDE": 52.7702045}, {"uprn": 10004000480.0, "standardised_address": "37, BENTLEY CLOSE, LOUGHBOROUGH, LE11 1SY", "standardised_postcode": "LE11 1SY", "LONGITUDE": -1.1970509, "LATITUDE": 52.7698738}, {"uprn": 200000844913.0, "standardised_address": "17, SADDLERS CLOSE, LOUGHBOROUGH, LE11 5HD", "standardised_postcode": "LE11 5HD", "LONGITUDE": -1.2189761, "LATITUDE": 52.7809828}, {"uprn": 100030549024.0, "standardised_address": "7, YEW TREE CRESCENT, MELTON MOWBRAY, LE13 1LN", "standardised_postcode": "LE13 1LN", "LONGITUDE": -0.8849264, "LATITUDE": 52.7756315}, {"uprn": 100030549068.0, "standardised_address": "51, YEW TREE CRESCENT, MELTON MOWBRAY, LE13 1LN", "standardised_postcode": "LE13 1LN", "LONGITUDE": -0.8856134, "LATITUDE": 52.7748558}, {"uprn": 2465087590.0, "standardised_address": "69, LOUGHBOROUGH ROAD, LEICESTER, LE4 5LL", "standardised_postcode": "LE4 5LL", "LONGITUDE": -1.1223645, "LATITUDE": 52.6532303}, {"uprn": 10033732069.0, "standardised_address": "118, HIGH STREET, EARL SHILTON, LEICESTER, LE9 7DG", "standardised_postcode": "LE9 7DG", "LONGITUDE": -1.3115505, "LATITUDE": 52.5764223}, {"uprn": 100032081116.0, "standardised_address": "22 Peter Dyer Court, Seacroft Road", "standardised_postcode": "LN12 2DT", "LONGITUDE": 0.2614919, "LATITUDE": 53.3389736}, {"uprn": 72266102.0, "standardised_address": "24, Petersfield Avenue", "standardised_postcode": "LS10 3PF", "LONGITUDE": -1.5282803, "LATITUDE": 53.7589478}, {"uprn": 72266110.0, "standardised_address": "35, PETERSFIELD AVENUE, LEEDS, LS10 3PF", "standardised_postcode": "LS10 3PF", "LONGITUDE": -1.5279768, "LATITUDE": 53.7589556}, {"uprn": 72304733.0, "standardised_address": "2, Warwick Court, Horsforth", "standardised_postcode": "LS18 4TB", "LONGITUDE": -1.6366988, "LATITUDE": 53.8328644}, {"uprn": 100080154916.0, "standardised_address": "16, IVY ROAD, LUTON, LU1 1DN", "standardised_postcode": "LU1 1DN", "LONGITUDE": -0.4296342, "LATITUDE": 51.8852366}, {"uprn": 100080163981.0, "standardised_address": "51, Newcombe Road", "standardised_postcode": "LU1 1LH", "LONGITUDE": -0.4315661, "LATITUDE": 51.880245}, {"uprn": 100080171727.0, "standardised_address": "85, Runley Road", "standardised_postcode": "LU1 1TX", "LONGITUDE": -0.4477962, "LATITUDE": 51.881881}, {"uprn": 100080141071.0, "standardised_address": "22, DELPHINE CLOSE, LUTON, LU1 5RE", "standardised_postcode": "LU1 5RE", "LONGITUDE": -0.4396275, "LATITUDE": 51.8756855}, {"uprn": 100080152967.0, "standardised_address": "187, HITCHIN ROAD, LUTON, LU2 0EP", "standardised_postcode": "LU2 0EP", "LONGITUDE": -0.4046343, "LATITUDE": 51.8875165}, {"uprn": 100080139727.0, "standardised_address": "89, CROMWELL ROAD, LUTON, LU3 1DP", "standardised_postcode": "LU3 1DP", "LONGITUDE": -0.4244653, "LATITUDE": 51.8859587}, {"uprn": 100080177405.0, "standardised_address": "81, SWAN MEAD, LUTON, LU4 0YP", "standardised_postcode": "LU4 0YP", "LONGITUDE": -0.4837081, "LATITUDE": 51.9040007}, {"uprn": 100080173090.0, "standardised_address": "28, Selbourne Road", "standardised_postcode": "LU4 8LP", "LONGITUDE": -0.4331933, "LATITUDE": 51.8894382}, {"uprn": 100080100758.0, "standardised_address": "15 MILL ROAD, HOUGHTON REGIS", "standardised_postcode": "LU5 5BD", "LONGITUDE": -0.5277522, "LATITUDE": 51.9026985}, {"uprn": 10001025868.0, "standardised_address": "43 KINGSLAND CLOSE, HOUGHTON REGIS", "standardised_postcode": "LU5 5UT", "LONGITUDE": -0.5022206, "LATITUDE": 51.9055144}, {"uprn": 10001025856.0, "standardised_address": "37 Kingsland Close, Houghton Regis", "standardised_postcode": "LU5 5UT", "LONGITUDE": -0.5027665, "LATITUDE": 51.9057101}, {"uprn": 10001023485.0, "standardised_address": "16, WILLOUGHBY CLOSE, DUNSTABLE, LU6 3TF", "standardised_postcode": "LU6 3TF", "LONGITUDE": -0.5131682, "LATITUDE": 51.8799288}, {"uprn": 100080120241.0, "standardised_address": "58, VIMY ROAD, LEIGHTON BUZZARD, LU7 1FQ", "standardised_postcode": "LU7 1FQ", "LONGITUDE": -0.6684013, "LATITUDE": 51.9218008}, {"uprn": 10001024491.0, "standardised_address": "11 Stephenson Close", "standardised_postcode": "LU7 2NE", "LONGITUDE": -0.6776464, "LATITUDE": 51.9125089}, {"uprn": 25002516.0, "standardised_address": "19, COTTESLOE COURT, STONY STRATFORD, MILTON KEYNES, MK11 1NL", "standardised_postcode": "MK11 1NL", "LONGITUDE": -0.8374092, "LATITUDE": 52.0540273}, {"uprn": 100080016298.0, "standardised_address": "11, Grafton Road", "standardised_postcode": "MK40 1DH", "LONGITUDE": -0.4762835, "LATITUDE": 52.1356448}, {"uprn": 100081334233.0, "standardised_address": "24, CHAUCER ROAD, BEDFORD, MK40 2AJ", "standardised_postcode": "MK40 2AJ", "LONGITUDE": -0.4820862, "LATITUDE": 52.1402846}, {"uprn": 10002971391.0, "standardised_address": "ROOM 5, 13, FOSTER HILL ROAD, BEDFORD, MK40 2ES", "standardised_postcode": "MK40 2ES", "LONGITUDE": -0.4680169, "LATITUDE": 52.141748}, {"uprn": 100080995116.0, "standardised_address": "27C, KIMBOLTON ROAD, BEDFORD, MK40 2NY", "standardised_postcode": "MK40 2NY", "LONGITUDE": -0.4587805, "LATITUDE": 52.1433879}, {"uprn": 10033179536.0, "standardised_address": "95, CROWE ROAD, BEDFORD, MK40 4FY", "standardised_postcode": "MK40 4FY", "LONGITUDE": -0.4812176, "LATITUDE": 52.1366436}, {"uprn": 10033179410.0, "standardised_address": "95, Henley Road", "standardised_postcode": "MK40 4FZ", "LONGITUDE": -0.4803204, "LATITUDE": 52.1355261}, {"uprn": 10033179403.0, "standardised_address": "81, HENLEY ROAD, BEDFORD, MK40 4FZ", "standardised_postcode": "MK40 4FZ", "LONGITUDE": -0.480418, "LATITUDE": 52.1356622}, {"uprn": 100080010125.0, "standardised_address": "19, CROMWELL ROAD, BEDFORD, MK40 4LR", "standardised_postcode": "MK40 4LR", "LONGITUDE": -0.482858, "LATITUDE": 52.1335177}, {"uprn": 100080025762.0, "standardised_address": "95, Mallard Hill", "standardised_postcode": "MK41 7QU", "LONGITUDE": -0.4682452, "LATITUDE": 52.1531728}, {"uprn": 10002966181.0, "standardised_address": "22, LEWES GARDENS, BEDFORD, MK41 8NW", "standardised_postcode": "MK41 8NW", "LONGITUDE": -0.4331692, "LATITUDE": 52.1566033}, {"uprn": 10002966183.0, "standardised_address": "26, Lewes Gardens", "standardised_postcode": "MK41 8NW", "LONGITUDE": -0.4333292, "LATITUDE": 52.1566506}, {"uprn": 10002966213.0, "standardised_address": "58, EXETER WALK, BEDFORD, MK41 8QN", "standardised_postcode": "MK41 8QN", "LONGITUDE": -0.4327389, "LATITUDE": 52.1573743}, {"uprn": 100080011160.0, "standardised_address": "12 Devizes Avenue, Bedford, MK41 8QT", "standardised_postcode": "MK41 8QT", "LONGITUDE": -0.4345664, "LATITUDE": 52.1569295}, {"uprn": 100080993516.0, "standardised_address": "11 RAGLAN COURT, DEVIZES AVENUE, BEDFORD, MK41 8QT", "standardised_postcode": "MK41 8QT", "LONGITUDE": -0.4341117, "LATITUDE": 52.1565548}, {"uprn": 10002966248.0, "standardised_address": "112, EXETER WALK, BEDFORD, MK41 8QW", "standardised_postcode": "MK41 8QW", "LONGITUDE": -0.4350041, "LATITUDE": 52.1573586}, {"uprn": 100080023488.0, "standardised_address": "1, Kirkman Close", "standardised_postcode": "MK42 0HY", "LONGITUDE": -0.4560605, "LATITUDE": 52.1251283}, {"uprn": 100080994421.0, "standardised_address": "16, BARTRAM COURT, 123, HIGH STREET, KEMPSTON, BEDFORD, MK42 7BP", "standardised_postcode": "MK42 7BP", "LONGITUDE": -0.505862, "LATITUDE": 52.1144562}, {"uprn": 100080020671.0, "standardised_address": "227, Hillgrounds Road, Kempston", "standardised_postcode": "MK42 8HW", "LONGITUDE": -0.4966793, "LATITUDE": 52.1269081}, {"uprn": 100080020676.0, "standardised_address": "237, Hillgrounds Road, Kempston", "standardised_postcode": "MK42 8HW", "LONGITUDE": -0.4962226, "LATITUDE": 52.1270414}, {"uprn": 100080037472.0, "standardised_address": "98, St. Johns Avenue, Kempston", "standardised_postcode": "MK42 8JR", "LONGITUDE": -0.4971843, "LATITUDE": 52.1133086}, {"uprn": 100081210880.0, "standardised_address": "64, AMPTHILL ROAD, BEDFORD, MK42 9HP", "standardised_postcode": "MK42 9HP", "LONGITUDE": -0.4711524, "LATITUDE": 52.1257766}, {"uprn": 10002970239.0, "standardised_address": "17, Davis Close", "standardised_postcode": "MK42 9LG", "LONGITUDE": -0.467977, "LATITUDE": 52.1232364}, {"uprn": 100080049331.0, "standardised_address": "26, Burridge Close, Marston Moretaine", "standardised_postcode": "MK43 0SG", "LONGITUDE": -0.5481185, "LATITUDE": 52.0673686}, {"uprn": 100080008976.0, "standardised_address": "5, Colley Close, Colmworth", "standardised_postcode": "MK44 2HE", "LONGITUDE": -0.3845779, "LATITUDE": 52.2116856}, {"uprn": 100080047408.0, "standardised_address": "86, Ailesbury Road, Ampthill", "standardised_postcode": "MK45 2XD", "LONGITUDE": -0.4882962, "LATITUDE": 52.0291749}, {"uprn": 10014614558.0, "standardised_address": "1 Pembroke Close, Houghton Conquest", "standardised_postcode": "MK45 3FH", "LONGITUDE": -0.4761796, "LATITUDE": 52.0615268}, {"uprn": 100080051765.0, "standardised_address": "2 FISHERS CLOSE, UPPER GRAVENHURST", "standardised_postcode": "MK45 4LJ", "LONGITUDE": -0.3766392, "LATITUDE": 52.0106445}, {"uprn": 25068208.0, "standardised_address": "14, Colne, Tinkers Bridge", "standardised_postcode": "MK6 3DJ", "LONGITUDE": -0.7241388, "LATITUDE": 52.0203873}, {"uprn": 25069053.0, "standardised_address": "185, BEADLEMEAD, NETHERFIELD, MILTON KEYNES, MK6 4HU", "standardised_postcode": "MK6 4HU", "LONGITUDE": -0.7286182, "LATITUDE": 52.0202019}, {"uprn": 25052926.0, "standardised_address": "56, CHERVIL, BEANHILL, MILTON KEYNES, MK6 4LG", "standardised_postcode": "MK6 4LG", "LONGITUDE": -0.7383444, "LATITUDE": 52.0184541}, {"uprn": 25054338.0, "standardised_address": "12, Osprey Close, Eaglestone", "standardised_postcode": "MK6 5BQ", "LONGITUDE": -0.7403678, "LATITUDE": 52.0299488}, {"uprn": 10093919581.0, "standardised_address": "9, ABIGAR CLOSE, WHITEHOUSE, MILTON KEYNES, MK8 1EN", "standardised_postcode": "MK8 1EN", "LONGITUDE": -0.8157866, "LATITUDE": 52.0314226}, {"uprn": 100031517329.0, "standardised_address": "37 Abbey Lodge, Baslow Drive, Beeston, Nottingham, NG9 2RZ", "standardised_postcode": "NG9 2RZ", "LONGITUDE": -1.207631, "LATITUDE": 52.9383028}, {"uprn": 100031531710.0, "standardised_address": "68 Abbey Lodge, Charles Avenue, Beeston, Nottingham, NG9 2SY", "standardised_postcode": "NG9 2SY", "LONGITUDE": -1.2088379, "LATITUDE": 52.938212}, {"uprn": 100031074426.0, "standardised_address": "13, ST. DUNSTANS CLOSE, KETTERING, NN15 5JE", "standardised_postcode": "NN15 5JE", "LONGITUDE": -0.6934448, "LATITUDE": 52.3923711}, {"uprn": 100031074430.0, "standardised_address": "17, St. Dunstans Close", "standardised_postcode": "NN15 5JE", "LONGITUDE": -0.6933767, "LATITUDE": 52.3921905}, {"uprn": 15007202.0, "standardised_address": "4, Kirton End", "standardised_postcode": "NN3 8FD", "LONGITUDE": -0.8198817, "LATITUDE": 52.267948}, {"uprn": 15007203.0, "standardised_address": "5, Kirton End", "standardised_postcode": "NN3 8FD", "LONGITUDE": -0.8198954, "LATITUDE": 52.2679841}, {"uprn": 10000861159.0, "standardised_address": "8, CLUNY WAY, ARLESEY, SG15 6ZB", "standardised_postcode": "SG15 6ZB", "LONGITUDE": -0.2630433, "LATITUDE": 52.0124857}, {"uprn": 100080067685.0, "standardised_address": "20, Reynolds Close", "standardised_postcode": "SG18 0QL", "LONGITUDE": -0.2602507, "LATITUDE": 52.0913964}, {"uprn": 100080067686.0, "standardised_address": "21 REYNOLDS CLOSE, BIGGLESWADE", "standardised_postcode": "SG18 0QL", "LONGITUDE": -0.2603335, "LATITUDE": 52.091385}, {"uprn": 100080080505.0, "standardised_address": "24, SKIPTON CLOSE, SANDY, SG19 1UB", "standardised_postcode": "SG19 1UB", "LONGITUDE": -0.2865906, "LATITUDE": 52.1338632}, {"uprn": 83104312.0, "standardised_address": "59, Johnson Street", "standardised_postcode": "WF14 8PQ", "LONGITUDE": -1.6989579, "LATITUDE": 53.670334}, {"uprn": 83177389.0, "standardised_address": "11, Primrose Gardens", "standardised_postcode": "WF17 0PZ", "LONGITUDE": -1.6201405, "LATITUDE": 53.7163994}, {"uprn": 83142904.0, "standardised_address": "64, Low Lane, Birstall", "standardised_postcode": "WF17 9HD", "LONGITUDE": -1.6661726, "LATITUDE": 53.7324005}, {"uprn": 83143336.0, "standardised_address": "7, MUSGRAVE STREET, BIRSTALL, BATLEY, WF17 9PF", "standardised_postcode": "WF17 9PF", "LONGITUDE": -1.6664882, "LATITUDE": 53.7322235}, {"uprn": 63013649.0, "standardised_address": "13, Broadacre Road", "standardised_postcode": "WF5 0QR", "LONGITUDE": -1.5691375, "LATITUDE": 53.6774393}, {"uprn": 10000832751.0, "standardised_address": "3, JUBILEE VILLAS, MAMBLE, KIDDERMINSTER, DY14 9JH", "standardised_postcode": "DY14 9JH", "LONGITUDE": -2.4549656, "LATITUDE": 52.3407598}, {"uprn": 10014089919.0, "standardised_address": "4, Spilsbury View, Mamble", "standardised_postcode": "DY14 9JJ", "LONGITUDE": -2.4544103, "LATITUDE": 52.3410046}, {"uprn": 10000830555.0, "standardised_address": "6, The Leasowes, Bayton", "standardised_postcode": "DY14 9NA", "LONGITUDE": -2.4474051, "LATITUDE": 52.3566115}, {"uprn": 100120589226.0, "standardised_address": "7 The Beeches, Mamble", "standardised_postcode": "DY14 9PD", "LONGITUDE": -2.4558902, "LATITUDE": 52.3407472}, {"uprn": 100121247799.0, "standardised_address": "14, Wesley Court, All Saints Road", "standardised_postcode": "GL1 4EF", "LONGITUDE": -2.2377897, "LATITUDE": 51.8605575}, {"uprn": 100120502788.0, "standardised_address": "28, BRAMBLE DRIVE, CAM, DURSLEY, GL11 5PX", "standardised_postcode": "GL11 5PX", "LONGITUDE": -2.362587, "LATITUDE": 51.6908247}, {"uprn": 100120502765.0, "standardised_address": "5, Bramble Drive, Cam", "standardised_postcode": "GL11 5PX", "LONGITUDE": -2.3621281, "LATITUDE": 51.6913296}, {"uprn": 10006832500.0, "standardised_address": "65, Midland Court", "standardised_postcode": "GL7 1JZ", "LONGITUDE": -1.9623299, "LATITUDE": 51.7089224}, {"uprn": 10009135124.0, "standardised_address": "45, Sapperton", "standardised_postcode": "GL7 6LQ", "LONGITUDE": -2.0804444, "LATITUDE": 51.7270088}, {"uprn": 200002589431.0, "standardised_address": "6, Caldervale, Bodenham", "standardised_postcode": "HR1 3LB", "LONGITUDE": -2.6677089, "LATITUDE": 52.1597419}, {"uprn": 200002599852.0, "standardised_address": "6, Cornewall Close, Moccas", "standardised_postcode": "HR2 9LG", "LONGITUDE": -2.9400679, "LATITUDE": 52.0787247}, {"uprn": 200002600043.0, "standardised_address": "12, Gosmore Road, Clehonger", "standardised_postcode": "HR2 9SN", "LONGITUDE": -2.8030098, "LATITUDE": 52.0335617}, {"uprn": 200002600713.0, "standardised_address": "6, THE COURTLANDS, WINFORTON, HEREFORD, HR3 6EF", "standardised_postcode": "HR3 6EF", "LONGITUDE": -3.0308025, "LATITUDE": 52.117301}, {"uprn": 200002600714.0, "standardised_address": "7, The Courtlands, Winforton", "standardised_postcode": "HR3 6EF", "LONGITUDE": -3.0309782, "LATITUDE": 52.1173174}, {"uprn": 200002600633.0, "standardised_address": "25 WEST VIEW, ALMELEY", "standardised_postcode": "HR3 6LE", "LONGITUDE": -2.9765856, "LATITUDE": 52.1599482}, {"uprn": 200002600640.0, "standardised_address": "9 WEST VIEW, ALMELEY", "standardised_postcode": "HR3 6LE", "LONGITUDE": -2.9776456, "LATITUDE": 52.1602901}, {"uprn": 10009580850.0, "standardised_address": "Questmore Cottage, Eardisley", "standardised_postcode": "HR3 6LW", "LONGITUDE": -3.0174005, "LATITUDE": 52.1638316}, {"uprn": 200002600667.0, "standardised_address": "2, Manor Close, Almeley", "standardised_postcode": "HR3 6NF", "LONGITUDE": -2.9777219, "LATITUDE": 52.159768}, {"uprn": 200002600745.0, "standardised_address": "18 ORCHARD CLOSE, EARDISLEY", "standardised_postcode": "HR3 6NP", "LONGITUDE": -3.0049396, "LATITUDE": 52.1369089}, {"uprn": 200002630372.0, "standardised_address": "7 NEW BARNFIELDS, STRETTON SUGWAS", "standardised_postcode": "HR4 7AZ", "LONGITUDE": -2.7937164, "LATITUDE": 52.0784081}, {"uprn": 200002630153.0, "standardised_address": "15 Brookside, Canon Pyon", "standardised_postcode": "HR4 8NY", "LONGITUDE": -2.7860426, "LATITUDE": 52.1366665}, {"uprn": 10007371180.0, "standardised_address": "1 CUCKOO PEN, KINGS PYON, HEREFORD, HR4 8PT", "standardised_postcode": "HR4 8PT", "LONGITUDE": -2.8223066, "LATITUDE": 52.1517035}, {"uprn": 10007360456.0, "standardised_address": "Flat 3, Whitehill House, Kington Road, Weobley, Herefordshire, County of, HR4 8QT", "standardised_postcode": "HR4 8QT", "LONGITUDE": -2.8871351, "LATITUDE": 52.1637664}, {"uprn": 10007360557.0, "standardised_address": "4 The Close, Burton Gardens, Weobley, Herefordshire, County of, HR4 8RQ", "standardised_postcode": "HR4 8RQ", "LONGITUDE": -2.8713531, "LATITUDE": 52.158175}, {"uprn": 200002606366.0, "standardised_address": "26, Burton Gardens, Weobley", "standardised_postcode": "HR4 8SR", "LONGITUDE": -2.870072, "LATITUDE": 52.1584452}, {"uprn": 200002606471.0, "standardised_address": "19 BURTON CRESCENT, WEOBLEY", "standardised_postcode": "HR4 8TB", "LONGITUDE": -2.8686872, "LATITUDE": 52.157898}, {"uprn": 200002610232.0, "standardised_address": "Flat 18, Caldwell Court, Walmer Street, Herefordshire, County of, HR4 9JD", "standardised_postcode": "HR4 9JD", "LONGITUDE": -2.7209647, "LATITUDE": 52.0587273}, {"uprn": 200002610239.0, "standardised_address": "Flat 25, Caldwell Court, Walmer Street, Herefordshire, County of, HR4 9JD", "standardised_postcode": "HR4 9JD", "LONGITUDE": -2.720922, "LATITUDE": 52.0587905}, {"uprn": 10007369692.0, "standardised_address": "29, GREENFIELDS, KINGTON, HR5 3AA", "standardised_postcode": "HR5 3AA", "LONGITUDE": -3.0276747, "LATITUDE": 52.2055563}, {"uprn": 200002611192.0, "standardised_address": "2, THE CRESCENT, KINGTON, HR5 3AS", "standardised_postcode": "HR5 3AS", "LONGITUDE": -3.03446, "LATITUDE": 52.2028267}, {"uprn": 200002610772.0, "standardised_address": "14, PARK ROAD, KINGTON, HR5 3AW", "standardised_postcode": "HR5 3AW", "LONGITUDE": -3.0366914, "LATITUDE": 52.2025104}, {"uprn": 200002611451.0, "standardised_address": "Flat 6 The Old Mill, 1, The Square", "standardised_postcode": "HR5 3BA", "LONGITUDE": -3.0321263, "LATITUDE": 52.2040909}, {"uprn": 200002610986.0, "standardised_address": "41, HATTON GARDENS, KINGTON, HR5 3DD", "standardised_postcode": "HR5 3DD", "LONGITUDE": -3.0211028, "LATITUDE": 52.2054965}, {"uprn": 200002611663.0, "standardised_address": "10, PASSEY COURT, THE SQUARE, KINGTON, HR5 3EE", "standardised_postcode": "HR5 3EE", "LONGITUDE": -3.0313311, "LATITUDE": 52.2042027}, {"uprn": 200002611138.0, "standardised_address": "6 Markwick Close", "standardised_postcode": "HR5 3UE", "LONGITUDE": -3.0305986, "LATITUDE": 52.2022671}, {"uprn": 200002631485.0, "standardised_address": "15 Westland View, Luston", "standardised_postcode": "HR6 0EA", "LONGITUDE": -2.7559424, "LATITUDE": 52.2641453}, {"uprn": 200002611869.0, "standardised_address": "6, Stockton Rock, Kimbolton", "standardised_postcode": "HR6 0JE", "LONGITUDE": -2.705673, "LATITUDE": 52.2478961}, {"uprn": 200002611690.0, "standardised_address": "6, Hengrave Green, Ivington", "standardised_postcode": "HR6 0JL", "LONGITUDE": -2.771841, "LATITUDE": 52.2051174}, {"uprn": 200002611760.0, "standardised_address": "9, HENGRAVE GREEN, IVINGTON, LEOMINSTER, HR6 0JL", "standardised_postcode": "HR6 0JL", "LONGITUDE": -2.7726156, "LATITUDE": 52.2050583}, {"uprn": 200002631301.0, "standardised_address": "102, Humber Close, Steensbridge", "standardised_postcode": "HR6 0LT", "LONGITUDE": -2.6696194, "LATITUDE": 52.2115774}, {"uprn": 200002631307.0, "standardised_address": "108, HUMBER CLOSE, STEENSBRIDGE, LEOMINSTER, HR6 0LT", "standardised_postcode": "HR6 0LT", "LONGITUDE": -2.6688721, "LATITUDE": 52.2115187}, {"uprn": 200002631317.0, "standardised_address": "119, HUMBER CLOSE, STEENSBRIDGE, LEOMINSTER, HR6 0LT", "standardised_postcode": "HR6 0LT", "LONGITUDE": -2.6702553, "LATITUDE": 52.2110433}, {"uprn": 200002611946.0, "standardised_address": "19, Cherrybrook Close, Hope-under-Dinmore", "standardised_postcode": "HR6 0PW", "LONGITUDE": -2.7212073, "LATITUDE": 52.1716237}, {"uprn": 200002611963.0, "standardised_address": "34, Cherrybrook Close, Hope-under-Dinmore", "standardised_postcode": "HR6 0PW", "LONGITUDE": -2.7207064, "LATITUDE": 52.171393}, {"uprn": 200002611958.0, "standardised_address": "3, Cherrybrook Close, Hope-under-Dinmore", "standardised_postcode": "HR6 0PW", "LONGITUDE": -2.7198309, "LATITUDE": 52.1715062}, {"uprn": 200002611938.0, "standardised_address": "11, CHERRYBROOK CLOSE, HOPE-UNDER-DINMORE, LEOMINSTER, HR6 0PW", "standardised_postcode": "HR6 0PW", "LONGITUDE": -2.7205116, "LATITUDE": 52.1720055}, {"uprn": 10007361923.0, "standardised_address": "1, JOHN ABEL CLOSE, LEOMINSTER, HR6 8AG", "standardised_postcode": "HR6 8AG", "LONGITUDE": -2.7349774, "LATITUDE": 52.2227768}, {"uprn": 200002612332.0, "standardised_address": "1 FALCONER PLACE", "standardised_postcode": "HR6 8AP", "LONGITUDE": -2.7342632, "LATITUDE": 52.2265124}, {"uprn": 200002612389.0, "standardised_address": "31, Worcester Road", "standardised_postcode": "HR6 8AU", "LONGITUDE": -2.731483, "LATITUDE": 52.2248304}, {"uprn": 200002612795.0, "standardised_address": "7, Kenwater Close", "standardised_postcode": "HR6 8DL", "LONGITUDE": -2.7422995, "LATITUDE": 52.2299145}, {"uprn": 200002612771.0, "standardised_address": "12, Kenwater Close", "standardised_postcode": "HR6 8DL", "LONGITUDE": -2.7418443, "LATITUDE": 52.2298365}, {"uprn": 200002612893.0, "standardised_address": "22, PARADISE COURT, LEOMINSTER, HR6 8DY", "standardised_postcode": "HR6 8DY", "LONGITUDE": -2.7391676, "LATITUDE": 52.2308872}, {"uprn": 200002631238.0, "standardised_address": "97A, BRIDGE STREET, LEOMINSTER, HR6 8EA", "standardised_postcode": "HR6 8EA", "LONGITUDE": -2.74386, "LATITUDE": 52.2339146}, {"uprn": 200002612984.0, "standardised_address": "35, Ridgemoor Road", "standardised_postcode": "HR6 8EJ", "LONGITUDE": -2.7411285, "LATITUDE": 52.2331731}, {"uprn": 200002612993.0, "standardised_address": "51, RIDGEMOOR ROAD, LEOMINSTER, HR6 8EJ", "standardised_postcode": "HR6 8EJ", "LONGITUDE": -2.7409404, "LATITUDE": 52.2335823}, {"uprn": 200002613041.0, "standardised_address": "64, Ridgemoor Road", "standardised_postcode": "HR6 8EL", "LONGITUDE": -2.7395478, "LATITUDE": 52.2334921}, {"uprn": 200002613014.0, "standardised_address": "16, Ridgemoor Road", "standardised_postcode": "HR6 8EL", "LONGITUDE": -2.740019, "LATITUDE": 52.2327699}, {"uprn": 200002613032.0, "standardised_address": "48, RIDGEMOOR ROAD, LEOMINSTER, HR6 8EL", "standardised_postcode": "HR6 8EL", "LONGITUDE": -2.7390232, "LATITUDE": 52.2336483}, {"uprn": 200002613051.0, "standardised_address": "15, CHEATON CLOSE, LEOMINSTER, HR6 8EN", "standardised_postcode": "HR6 8EN", "LONGITUDE": -2.7391605, "LATITUDE": 52.233099}, {"uprn": 200002613143.0, "standardised_address": "66, CHEATON CLOSE, LEOMINSTER, HR6 8EW", "standardised_postcode": "HR6 8EW", "LONGITUDE": -2.7384096, "LATITUDE": 52.2328519}, {"uprn": 200002614594.0, "standardised_address": "73, BARGATES, LEOMINSTER, HR6 8HB", "standardised_postcode": "HR6 8HB", "LONGITUDE": -2.7446336, "LATITUDE": 52.22678}, {"uprn": 200002613305.0, "standardised_address": "5, PUMP PIECE, LEOMINSTER, HR6 8HR", "standardised_postcode": "HR6 8HR", "LONGITUDE": -2.7462416, "LATITUDE": 52.2248908}, {"uprn": 200002614704.0, "standardised_address": "34, SANDPITS, LEOMINSTER, HR6 8HT", "standardised_postcode": "HR6 8HT", "LONGITUDE": -2.7462558, "LATITUDE": 52.2239917}, {"uprn": 200002613457.0, "standardised_address": "2, GEORGE STREET, LEOMINSTER, HR6 8JZ", "standardised_postcode": "HR6 8JZ", "LONGITUDE": -2.741903, "LATITUDE": 52.2219602}, {"uprn": 200002613508.0, "standardised_address": "42, CROFT STREET, LEOMINSTER, HR6 8LA", "standardised_postcode": "HR6 8LA", "LONGITUDE": -2.7433093, "LATITUDE": 52.2228864}, {"uprn": 200002613514.0, "standardised_address": "50, Croft Street", "standardised_postcode": "HR6 8LA", "LONGITUDE": -2.7438936, "LATITUDE": 52.2228108}, {"uprn": 200002613493.0, "standardised_address": "29, Croft Street", "standardised_postcode": "HR6 8LA", "LONGITUDE": -2.7422535, "LATITUDE": 52.2227852}, {"uprn": 200002613536.0, "standardised_address": "3, CONINGSBY ROAD, LEOMINSTER, HR6 8LL", "standardised_postcode": "HR6 8LL", "LONGITUDE": -2.7388428, "LATITUDE": 52.2241091}, {"uprn": 200002613531.0, "standardised_address": "11, CONINGSBY ROAD, LEOMINSTER, HR6 8LL", "standardised_postcode": "HR6 8LL", "LONGITUDE": -2.7383178, "LATITUDE": 52.2239957}, {"uprn": 200002613553.0, "standardised_address": "1, Eaton Close", "standardised_postcode": "HR6 8LQ", "LONGITUDE": -2.7378856, "LATITUDE": 52.2242331}, {"uprn": 200002631267.0, "standardised_address": "14, EATON CLOSE, LEOMINSTER, HR6 8LQ", "standardised_postcode": "HR6 8LQ", "LONGITUDE": -2.7374908, "LATITUDE": 52.2251436}, {"uprn": 200002613566.0, "standardised_address": "22, EATON CLOSE, LEOMINSTER, HR6 8LQ", "standardised_postcode": "HR6 8LQ", "LONGITUDE": -2.7370288, "LATITUDE": 52.224652}, {"uprn": 200002616236.0, "standardised_address": "FLAT 7, NEWMAN HOUSE, RYELANDS ROAD, LEOMINSTER, HR6 8PD", "standardised_postcode": "HR6 8PD", "LONGITUDE": -2.7448232, "LATITUDE": 52.2235533}, {"uprn": 200002613680.0, "standardised_address": "29, HOLLAND ROAD, LEOMINSTER, HR6 8PF", "standardised_postcode": "HR6 8PF", "LONGITUDE": -2.7437325, "LATITUDE": 52.224556}, {"uprn": 200002613705.0, "standardised_address": "31, Mortimer Street", "standardised_postcode": "HR6 8PG", "LONGITUDE": -2.7425265, "LATITUDE": 52.2233499}, {"uprn": 200002613737.0, "standardised_address": "21, WIGMORE STREET, LEOMINSTER, HR6 8PJ", "standardised_postcode": "HR6 8PJ", "LONGITUDE": -2.7446163, "LATITUDE": 52.2223539}, {"uprn": 200002613761.0, "standardised_address": "15, Wigmore Street", "standardised_postcode": "HR6 8PL", "LONGITUDE": -2.7443457, "LATITUDE": 52.2227091}, {"uprn": 10007370335.0, "standardised_address": "8, MORTIMER CLOSE, LEOMINSTER, HR6 8PQ", "standardised_postcode": "HR6 8PQ", "LONGITUDE": -2.7423152, "LATITUDE": 52.2238457}, {"uprn": 10023974314.0, "standardised_address": "ROOM 2, LENDOR, 9, BUCKFIELD ROAD, LEOMINSTER, HEREFORDSHIRE, HR6 8SF", "standardised_postcode": "HR6 8SF", "LONGITUDE": -2.7549361, "LATITUDE": 52.2258208}, {"uprn": 200002616762.0, "standardised_address": "50, Portna Way", "standardised_postcode": "HR6 9AD", "LONGITUDE": -2.7679625, "LATITUDE": 52.2220362}, {"uprn": 200002616765.0, "standardised_address": "56, PORTNA WAY, LEOMINSTER, HR6 9AD", "standardised_postcode": "HR6 9AD", "LONGITUDE": -2.7681663, "LATITUDE": 52.221972}, {"uprn": 200002616784.0, "standardised_address": "6, Portna Way", "standardised_postcode": "HR6 9AE", "LONGITUDE": -2.7661266, "LATITUDE": 52.2216886}, {"uprn": 200002616770.0, "standardised_address": "13, Portna Way", "standardised_postcode": "HR6 9AE", "LONGITUDE": -2.7667581, "LATITUDE": 52.2218013}, {"uprn": 200002616815.0, "standardised_address": "28, FOOTWAY CROFT, LEOMINSTER, HR6 9AG", "standardised_postcode": "HR6 9AG", "LONGITUDE": -2.7674867, "LATITUDE": 52.2216078}, {"uprn": 200002616876.0, "standardised_address": "2, Curl View, Pembridge", "standardised_postcode": "HR6 9ET", "LONGITUDE": -2.8940396, "LATITUDE": 52.2194034}, {"uprn": 200002616880.0, "standardised_address": "6, Curl View, Pembridge", "standardised_postcode": "HR6 9ET", "LONGITUDE": -2.894712, "LATITUDE": 52.2193533}, {"uprn": 200002617122.0, "standardised_address": "11, Curl View Crescent, Pembridge", "standardised_postcode": "HR6 9HQ", "LONGITUDE": -2.8945024, "LATITUDE": 52.2198494}, {"uprn": 200002631408.0, "standardised_address": "39 THE GROVE, SHOBDON", "standardised_postcode": "HR6 9NF", "LONGITUDE": -2.8869065, "LATITUDE": 52.2511987}, {"uprn": 200002616906.0, "standardised_address": "18 MOOR MEADOW, SHOBDON", "standardised_postcode": "HR6 9NT", "LONGITUDE": -2.8840648, "LATITUDE": 52.2515397}, {"uprn": 10009574826.0, "standardised_address": "2 The Village, Yatton", "standardised_postcode": "HR6 9TL", "LONGITUDE": -2.8369525, "LATITUDE": 52.2958029}, {"uprn": 200002622624.0, "standardised_address": "10, MILLER CRADDOCK WAY, LEDBURY, HR8 2XT", "standardised_postcode": "HR8 2XT", "LONGITUDE": -2.4284905, "LATITUDE": 52.0307915}, {"uprn": 200002622657.0, "standardised_address": "10, ASTON CLOSE, LEDBURY, HR8 2XU", "standardised_postcode": "HR8 2XU", "LONGITUDE": -2.4271925, "LATITUDE": 52.0307153}, {"uprn": 200002622662.0, "standardised_address": "16, Aston Close", "standardised_postcode": "HR8 2XU", "LONGITUDE": -2.4278182, "LATITUDE": 52.0306051}, {"uprn": 100071536782.0, "standardised_address": "2, Findon Way", "standardised_postcode": "SY3 5NA", "LONGITUDE": -2.8027488, "LATITUDE": 52.7101477}, {"uprn": 100071536880.0, "standardised_address": "113, Lambourn Drive", "standardised_postcode": "SY3 5NF", "LONGITUDE": -2.8030195, "LATITUDE": 52.7106552}, {"uprn": 10009574764.0, "standardised_address": "2 THE BROOK, LINGEN, BUCKNELL, SY7 0DY", "standardised_postcode": "SY7 0DY", "LONGITUDE": -2.9317576, "LATITUDE": 52.2975198}, {"uprn": 200002628293.0, "standardised_address": "21 ROSEMARY, LEINTWARDINE", "standardised_postcode": "SY7 0LR", "LONGITUDE": -2.8731711, "LATITUDE": 52.3614144}, {"uprn": 200002628296.0, "standardised_address": "24 ROSEMARY, LEINTWARDINE", "standardised_postcode": "SY7 0LR", "LONGITUDE": -2.8730416, "LATITUDE": 52.360804}, {"uprn": 200002628400.0, "standardised_address": "10 Lowe Croft, Leintwardine", "standardised_postcode": "SY7 0NP", "LONGITUDE": -2.8736761, "LATITUDE": 52.3609612}, {"uprn": 200002628392.0, "standardised_address": "2, Lowe Croft, Leintwardine", "standardised_postcode": "SY7 0NP", "LONGITUDE": -2.8736537, "LATITUDE": 52.3605657}, {"uprn": 200002628536.0, "standardised_address": "4, HALLETS WELL, ORLETON, LUDLOW, SY8 4HH", "standardised_postcode": "SY8 4HH", "LONGITUDE": -2.7409679, "LATITUDE": 52.3020458}, {"uprn": 200002628506.0, "standardised_address": "10 ST GEORGES CRESCENT, ORLETON", "standardised_postcode": "SY8 4HL", "LONGITUDE": -2.7420943, "LATITUDE": 52.3018769}, {"uprn": 200002628470.0, "standardised_address": "8 GREEN LANE, ORLETON", "standardised_postcode": "SY8 4JE", "LONGITUDE": -2.7581608, "LATITUDE": 52.3023411}, {"uprn": 10007370967.0, "standardised_address": "15 The Avenue, Wyson, Brimfield, Herefordshire, County of, SY8 4NJ", "standardised_postcode": "SY8 4NJ", "LONGITUDE": -2.7028498, "LATITUDE": 52.3093186}, {"uprn": 100120590397.0, "standardised_address": "6, Spring Gardens", "standardised_postcode": "WR15 8BE", "LONGITUDE": -2.5918475, "LATITUDE": 52.3107187}, {"uprn": 100120590377.0, "standardised_address": "8, SCOTLAND PLACE, TENBURY WELLS, WR15 8BT", "standardised_postcode": "WR15 8BT", "LONGITUDE": -2.5949436, "LATITUDE": 52.3118989}, {"uprn": 100120590206.0, "standardised_address": "24, KYRESIDE, TENBURY WELLS, WR15 8BU", "standardised_postcode": "WR15 8BU", "LONGITUDE": -2.5948807, "LATITUDE": 52.3050216}, {"uprn": 100120590212.0, "standardised_address": "30, Kyreside", "standardised_postcode": "WR15 8BU", "LONGITUDE": -2.5946937, "LATITUDE": 52.306389}, {"uprn": 100120590223.0, "standardised_address": "41, KYRESIDE, TENBURY WELLS, WR15 8BU", "standardised_postcode": "WR15 8BU", "LONGITUDE": -2.5946878, "LATITUDE": 52.3059485}, {"uprn": 100120590253.0, "standardised_address": "71, KYRESIDE, TENBURY WELLS, WR15 8BX", "standardised_postcode": "WR15 8BX", "LONGITUDE": -2.5932704, "LATITUDE": 52.3041486}, {"uprn": 100120589910.0, "standardised_address": "1, Bromyard Road", "standardised_postcode": "WR15 8BZ", "LONGITUDE": -2.5950627, "LATITUDE": 52.3043733}, {"uprn": 100120590015.0, "standardised_address": "19, CRESCENT PLACE, TENBURY WELLS, WR15 8DF", "standardised_postcode": "WR15 8DF", "LONGITUDE": -2.5947732, "LATITUDE": 52.3024688}, {"uprn": 100120590467.0, "standardised_address": "13, THE CRESCENT, TENBURY WELLS, WR15 8DG", "standardised_postcode": "WR15 8DG", "LONGITUDE": -2.5943843, "LATITUDE": 52.3030012}, {"uprn": 100120590458.0, "standardised_address": "4, THE CRESCENT, TENBURY WELLS, WR15 8DG", "standardised_postcode": "WR15 8DG", "LONGITUDE": -2.5934407, "LATITUDE": 52.3026284}, {"uprn": 100120590555.0, "standardised_address": "61, WHEELER ORCHARD, TENBURY WELLS, WR15 8DQ", "standardised_postcode": "WR15 8DQ", "LONGITUDE": -2.5955391, "LATITUDE": 52.3016289}, {"uprn": 100120590504.0, "standardised_address": "10, Wheeler Orchard", "standardised_postcode": "WR15 8DQ", "LONGITUDE": -2.5972002, "LATITUDE": 52.303005}, {"uprn": 100120590505.0, "standardised_address": "11, Wheeler Orchard", "standardised_postcode": "WR15 8DQ", "LONGITUDE": -2.5973032, "LATITUDE": 52.3030315}, {"uprn": 100120590513.0, "standardised_address": "19 Wheeler Orchard", "standardised_postcode": "WR15 8DQ", "LONGITUDE": -2.5962211, "LATITUDE": 52.3032707}, {"uprn": 100120590539.0, "standardised_address": "45 Wheeler Orchard", "standardised_postcode": "WR15 8DQ", "LONGITUDE": -2.5953731, "LATITUDE": 52.3023669}, {"uprn": 100120590126.0, "standardised_address": "4, GRASSY BANK, TENBURY WELLS, WR15 8DR", "standardised_postcode": "WR15 8DR", "LONGITUDE": -2.5936679, "LATITUDE": 52.3020698}, {"uprn": 100120590355.0, "standardised_address": "22, PEMBROKE AVENUE, TENBURY WELLS, WR15 8EH", "standardised_postcode": "WR15 8EH", "LONGITUDE": -2.5950524, "LATITUDE": 52.3090753}, {"uprn": 100120594666.0, "standardised_address": "32 Pembroke Gardens, Pembroke Avenue", "standardised_postcode": "WR15 8EH", "LONGITUDE": -2.5954208, "LATITUDE": 52.3091994}, {"uprn": 10000832235.0, "standardised_address": "2 Cutmill Bridge, Eardiston", "standardised_postcode": "WR15 8JN", "LONGITUDE": -2.4455624, "LATITUDE": 52.3121523}, {"uprn": 10000832237.0, "standardised_address": "4 Cutmill Bridge, Eardiston", "standardised_postcode": "WR15 8JN", "LONGITUDE": -2.4453422, "LATITUDE": 52.3121352}, {"uprn": 10000832267.0, "standardised_address": "25, CUTMILL BRIDGE, EARDISTON, TENBURY WELLS, WR15 8JN", "standardised_postcode": "WR15 8JN", "LONGITUDE": -2.4442501, "LATITUDE": 52.311945}, {"uprn": 100120606489.0, "standardised_address": "3, Astley Orchard, Eastham", "standardised_postcode": "WR15 8NR", "LONGITUDE": -2.4883154, "LATITUDE": 52.3102573}, {"uprn": 100120606492.0, "standardised_address": "6 Astley Orchard, Eastham", "standardised_postcode": "WR15 8NR", "LONGITUDE": -2.4887428, "LATITUDE": 52.3104443}, {"uprn": 10000830371.0, "standardised_address": "1 Church Close, Stoke Bliss", "standardised_postcode": "WR15 8QJ", "LONGITUDE": -2.5145315, "LATITUDE": 52.2613192}, {"uprn": 100120590485.0, "standardised_address": "5 The Oaks, Stoke Bliss", "standardised_postcode": "WR15 8RR", "LONGITUDE": -2.5435427, "LATITUDE": 52.2649832}, {"uprn": 10014092735.0, "standardised_address": "5, Malt House Mews", "standardised_postcode": "WR15 8TZ", "LONGITUDE": -2.5954096, "LATITUDE": 52.312769}, {"uprn": 90120326.0, "standardised_address": "Flat 7, Beverley Court, Clarendon Place, Dudley, B62 9BE", "standardised_postcode": "B62 9BE", "LONGITUDE": -2.0159488, "LATITUDE": 52.4625896}, {"uprn": 90118998.0, "standardised_address": "FLAT 78, VICTORIA COURT, BINSWOOD ROAD, HALESOWEN, B62 9BQ", "standardised_postcode": "B62 9BQ", "LONGITUDE": -2.0145066, "LATITUDE": 52.4631112}, {"uprn": 32015926.0, "standardised_address": "62 Petford Street", "standardised_postcode": "B64 6DY", "LONGITUDE": -2.0714993, "LATITUDE": 52.4736718}, {"uprn": 32004728.0, "standardised_address": "16, RED BRICK CLOSE, CRADLEY HEATH, B64 7DR", "standardised_postcode": "B64 7DR", "LONGITUDE": -2.0758424, "LATITUDE": 52.4652633}, {"uprn": 32148048.0, "standardised_address": "2, Brailsford Drive", "standardised_postcode": "B66 3NH", "LONGITUDE": -1.9679894, "LATITUDE": 52.4929906}, {"uprn": 10008537133.0, "standardised_address": "FLAT 8, 45, CORBETT STREET, SMETHWICK, B66 3PU", "standardised_postcode": "B66 3PU", "LONGITUDE": -1.9616889, "LATITUDE": 52.4893028}, {"uprn": 32144722.0, "standardised_address": "67, Talbot Road", "standardised_postcode": "B66 4DX", "LONGITUDE": -1.9667612, "LATITUDE": 52.4810605}, {"uprn": 32146056.0, "standardised_address": "Flat 6, 179 Bearwood Road, Sandwell, B66 4LN", "standardised_postcode": "B66 4LN", "LONGITUDE": -1.9670378, "LATITUDE": 52.4852949}, {"uprn": 32146371.0, "standardised_address": "10, Clent View, Gilbert Road", "standardised_postcode": "B66 4PU", "LONGITUDE": -1.9602366, "LATITUDE": 52.4829554}, {"uprn": 32129152.0, "standardised_address": "120, VICARAGE ROAD, SMETHWICK, B67 7AP", "standardised_postcode": "B67 7AP", "LONGITUDE": -1.9765168, "LATITUDE": 52.4936489}, {"uprn": 32129140.0, "standardised_address": "105, Vicarage Road", "standardised_postcode": "B67 7AP", "LONGITUDE": -1.9763696, "LATITUDE": 52.4934421}, {"uprn": 32131232.0, "standardised_address": "6 The Oaks, South Road, Sandwell, B67 7BY", "standardised_postcode": "B67 7BY", "LONGITUDE": -1.9747203, "LATITUDE": 52.4930012}, {"uprn": 32131213.0, "standardised_address": "FLAT 1, 41, SOUTH ROAD, SMETHWICK, B67 7BZ", "standardised_postcode": "B67 7BZ", "LONGITUDE": -1.9742786, "LATITUDE": 52.4926236}, {"uprn": 200001483798.0, "standardised_address": "Flat 1, 5 North Street, Sandwell, B67 7DA", "standardised_postcode": "B67 7DA", "LONGITUDE": -1.975265, "LATITUDE": 52.4933789}, {"uprn": 32131139.0, "standardised_address": "16 St. Albans Close", "standardised_postcode": "B67 7PD", "LONGITUDE": -1.9806101, "LATITUDE": 52.4966882}, {"uprn": 32130313.0, "standardised_address": "31, White Road", "standardised_postcode": "B67 7PG", "LONGITUDE": -1.978032, "LATITUDE": 52.4974969}, {"uprn": 32067588.0, "standardised_address": "12, COTSWOLD CLOSE, OLDBURY, B69 1FB", "standardised_postcode": "B69 1FB", "LONGITUDE": -2.0284188, "LATITUDE": 52.490672}, {"uprn": 32067603.0, "standardised_address": "40, Wolverley Crescent", "standardised_postcode": "B69 1FD", "LONGITUDE": -2.0298473, "LATITUDE": 52.4906267}, {"uprn": 32067644.0, "standardised_address": "22, WITLEY CRESCENT, OLDBURY, B69 1FF", "standardised_postcode": "B69 1FF", "LONGITUDE": -2.0285806, "LATITUDE": 52.4904562}, {"uprn": 32086384.0, "standardised_address": "45 COYNE ROAD, WEST BROMWICH", "standardised_postcode": "B70 7HJ", "LONGITUDE": -2.0035014, "LATITUDE": 52.5127458}, {"uprn": 100120639219.0, "standardised_address": "21 MUSKETTS COURT, BIRCHFIELD ROAD, REDDITCH", "standardised_postcode": "B97 4NA", "LONGITUDE": -1.958538, "LATITUDE": 52.2974523}, {"uprn": 100120639206.0, "standardised_address": "8 MUSKETTS COURT, BIRCHFIELD ROAD, REDDITCH", "standardised_postcode": "B97 4NA", "LONGITUDE": -1.9586844, "LATITUDE": 52.2972294}, {"uprn": 100070622454.0, "standardised_address": "24, Boyd Close", "standardised_postcode": "CV2 2NF", "LONGITUDE": -1.4423782, "LATITUDE": 52.431865}, {"uprn": 100070665874.0, "standardised_address": "4 JONATHAN ROAD, COVENTRY", "standardised_postcode": "CV2 2NQ", "LONGITUDE": -1.4423682, "LATITUDE": 52.4326561}, {"uprn": 100070665876.0, "standardised_address": "6 JONATHAN ROAD", "standardised_postcode": "CV2 2NQ", "LONGITUDE": -1.4423971, "LATITUDE": 52.4326922}, {"uprn": 100071505169.0, "standardised_address": "192, Leam Terrace", "standardised_postcode": "CV31 1DW", "LONGITUDE": -1.5185861, "LATITUDE": 52.2852891}, {"uprn": 10013181859.0, "standardised_address": "121 Radford Road", "standardised_postcode": "CV31 1JZ", "LONGITUDE": -1.5185861, "LATITUDE": 52.2852891}, {"uprn": 100071252300.0, "standardised_address": "21 EPPERSTONE COURT, AVENUE ROAD, LEAMINGTON SPA, CV31 3NH", "standardised_postcode": "CV31 3NH", "LONGITUDE": -1.5363462, "LATITUDE": 52.2854703}, {"uprn": 100070246806.0, "standardised_address": "38 Whittle Court, Upper Holly Walk", "standardised_postcode": "CV32 4LB", "LONGITUDE": -1.5250688, "LATITUDE": 52.2917237}, {"uprn": 100070246778.0, "standardised_address": "9 Whittle Court, Upper Holly Walk", "standardised_postcode": "CV32 4LB", "LONGITUDE": -1.5250688, "LATITUDE": 52.2917237}, {"uprn": 100070246783.0, "standardised_address": "15 Whittle Court, Upper Holly Walk", "standardised_postcode": "CV32 4LB", "LONGITUDE": -1.5250688, "LATITUDE": 52.2917237}, {"uprn": 100071254640.0, "standardised_address": "8 Leicester Court, Leicester Street", "standardised_postcode": "CV32 4UD", "LONGITUDE": -1.523885, "LATITUDE": 52.2947491}, {"uprn": 100071256971.0, "standardised_address": "20 STUART COURT, WARWICK TERRACE, LEAMINGTON SPA, CV32 5NU", "standardised_postcode": "CV32 5NU", "LONGITUDE": -1.5418657, "LATITUDE": 52.2922215}, {"uprn": 10003791898.0, "standardised_address": "17 Goode Close", "standardised_postcode": "CV34 5LP", "LONGITUDE": -1.6014186, "LATITUDE": 52.2866675}, {"uprn": 100070262028.0, "standardised_address": "9, Grange Close", "standardised_postcode": "CV34 5PE", "LONGITUDE": -1.5601131, "LATITUDE": 52.2884158}, {"uprn": 100070645529.0, "standardised_address": "28, Ensign Close", "standardised_postcode": "CV4 9TU", "LONGITUDE": -1.5962218, "LATITUDE": 52.4031891}, {"uprn": 10023037940.0, "standardised_address": "57 Dunster Place", "standardised_postcode": "CV6 4JD", "LONGITUDE": -1.4997454, "LATITUDE": 52.4441734}, {"uprn": 100071341257.0, "standardised_address": "45, THE FIRS, MAXSTOKE LANE, MERIDEN, COVENTRY, CV7 7NT", "standardised_postcode": "CV7 7NT", "LONGITUDE": -1.6515841, "LATITUDE": 52.4397024}, {"uprn": 100071341250.0, "standardised_address": "38, The Firs, Maxstoke Lane", "standardised_postcode": "CV7 7NT", "LONGITUDE": -1.651866, "LATITUDE": 52.4394065}, {"uprn": 90114588.0, "standardised_address": "Flat 2, 20 Wellington Road, Dudley, DY1 1RB", "standardised_postcode": "DY1 1RB", "LONGITUDE": -2.0956881, "LATITUDE": 52.5076633}, {"uprn": 90000273.0, "standardised_address": "36, Edenbridge View", "standardised_postcode": "DY1 2JJ", "LONGITUDE": -2.1174047, "LATITUDE": 52.5187103}, {"uprn": 100120753988.0, "standardised_address": "Flat 1, Hargreaves Court, Parry Road, Wyre Forest, DY11 6LZ", "standardised_postcode": "DY11 6LZ", "LONGITUDE": -2.2655377, "LATITUDE": 52.3760041}, {"uprn": 90094063.0, "standardised_address": "11, IVANHOE STREET, DUDLEY, DY2 0YB", "standardised_postcode": "DY2 0YB", "LONGITUDE": -2.1002305, "LATITUDE": 52.5032005}, {"uprn": 90094168.0, "standardised_address": "129, Ivanhoe Street", "standardised_postcode": "DY2 0YD", "LONGITUDE": -2.0989799, "LATITUDE": 52.5038938}, {"uprn": 90126107.0, "standardised_address": "FLAT 1, 26, NORTH STREET, DUDLEY, DY2 7DU", "standardised_postcode": "DY2 7DU", "LONGITUDE": -2.0756107, "LATITUDE": 52.5100603}, {"uprn": 90009856.0, "standardised_address": "30, Lauder Close", "standardised_postcode": "DY3 3XN", "LONGITUDE": -2.1305593, "LATITUDE": 52.5466641}, {"uprn": 10013825938.0, "standardised_address": "21, SHEPHERDS DROVE, WEST ASHTON, TROWBRIDGE, BA14 6DG", "standardised_postcode": "BA14 6DG", "LONGITUDE": -2.1703744, "LATITUDE": 51.2959889}, {"uprn": 100121084534.0, "standardised_address": "68, BARN GLEBE, TROWBRIDGE, BA14 7JZ", "standardised_postcode": "BA14 7JZ", "LONGITUDE": -2.194204, "LATITUDE": 51.3212819}, {"uprn": 250045056.0, "standardised_address": "116, WOOKEY HOLE ROAD, WELLS, BA5 2NQ", "standardised_postcode": "BA5 2NQ", "LONGITUDE": -2.6618111, "LATITUDE": 51.2154525}, {"uprn": 100040783250.0, "standardised_address": "210, WINDHAM ROAD, BOURNEMOUTH, BH1 4QX", "standardised_postcode": "BH1 4QX", "LONGITUDE": -1.8485583, "LATITUDE": 50.7304686}, {"uprn": 100040728126.0, "standardised_address": "34, Copper Beech Gardens", "standardised_postcode": "BH10 5DB", "LONGITUDE": -1.8917906, "LATITUDE": 50.7540873}, {"uprn": 100040753089.0, "standardised_address": "Flat 2, Portiere House, 10 Moore Avenue, Bournemouth, Christchurch and Poole, BH11 8AY", "standardised_postcode": "BH11 8AY", "LONGITUDE": -1.9112837, "LATITUDE": 50.7610641}, {"uprn": 100040761568.0, "standardised_address": "11 RAGLAN GARDENS, BOURNEMOUTH", "standardised_postcode": "BH11 8QU", "LONGITUDE": -1.9130825, "LATITUDE": 50.7542938}, {"uprn": 100040820003.0, "standardised_address": "41, Merrow Avenue", "standardised_postcode": "BH12 1PY", "LONGITUDE": -1.9063404, "LATITUDE": 50.7368871}, {"uprn": 100040827450.0, "standardised_address": "335b, Ringwood Road", "standardised_postcode": "BH12 3JN", "LONGITUDE": -1.9462039, "LATITUDE": 50.7421399}, {"uprn": 100040813791.0, "standardised_address": "18 Jellicoe Close, Bournemouth, Christchurch and Poole, BH14 0PX", "standardised_postcode": "BH14 0PX", "LONGITUDE": -1.960793, "LATITUDE": 50.72879}, {"uprn": 100040821208.0, "standardised_address": "Flat 6, Ashley Mount, 7 Mount Road, Bournemouth, Christchurch and Poole, BH14 0QW", "standardised_postcode": "BH14 0QW", "LONGITUDE": -1.9495564, "LATITUDE": 50.7293428}, {"uprn": 10001086391.0, "standardised_address": "10 MANTON CLOSE, POOLE", "standardised_postcode": "BH15 4QA", "LONGITUDE": -2.0098437, "LATITUDE": 50.7207753}, {"uprn": 100040827073.0, "standardised_address": "1, RICE TERRACE, POOLE, BH16 5DH", "standardised_postcode": "BH16 5DH", "LONGITUDE": -2.0197173, "LATITUDE": 50.7266588}, {"uprn": 100040827063.0, "standardised_address": "3 Rice Gardens", "standardised_postcode": "BH16 5DJ", "LONGITUDE": -2.01989, "LATITUDE": 50.7264753}, {"uprn": 100040607845.0, "standardised_address": "16 WARBLER CLOSE, UPTON", "standardised_postcode": "BH16 5RL", "LONGITUDE": -2.0316176, "LATITUDE": 50.742003}, {"uprn": 100040824517.0, "standardised_address": "Flat 14, Tanglewood Lodge, 89a Petersham Road, Bournemouth, Christchurch and Poole, BH17 7DW", "standardised_postcode": "BH17 7DW", "LONGITUDE": -2.0037117, "LATITUDE": 50.742439}, {"uprn": 10001087039.0, "standardised_address": "59, DEWLISH CLOSE, POOLE, BH17 8AQ", "standardised_postcode": "BH17 8AQ", "LONGITUDE": -1.9568173, "LATITUDE": 50.7539593}, {"uprn": 10001087048.0, "standardised_address": "77, Dewlish Close", "standardised_postcode": "BH17 8AQ", "LONGITUDE": -1.9563924, "LATITUDE": 50.7535454}, {"uprn": 100040799312.0, "standardised_address": "60, Chaldon Road", "standardised_postcode": "BH17 8DB", "LONGITUDE": -1.9598665, "LATITUDE": 50.7524496}, {"uprn": 100040799318.0, "standardised_address": "66, Chaldon Road", "standardised_postcode": "BH17 8DB", "LONGITUDE": -1.9600812, "LATITUDE": 50.7526369}, {"uprn": 100040799326.0, "standardised_address": "74, Chaldon Road", "standardised_postcode": "BH17 8DB", "LONGITUDE": -1.9604614, "LATITUDE": 50.7528353}, {"uprn": 100040799344.0, "standardised_address": "92, CHALDON ROAD, POOLE, BH17 8DB", "standardised_postcode": "BH17 8DB", "LONGITUDE": -1.9604477, "LATITUDE": 50.7524138}, {"uprn": 200004823359.0, "standardised_address": "12, Marsh Way", "standardised_postcode": "BH19 2TE", "LONGITUDE": -1.9770611, "LATITUDE": 50.6078225}, {"uprn": 200004825497.0, "standardised_address": "67 MARSH WAY, SWANAGE", "standardised_postcode": "BH19 2TE", "LONGITUDE": -1.9787943, "LATITUDE": 50.6087743}, {"uprn": 200004825492.0, "standardised_address": "57 MARSH WAY, SWANAGE", "standardised_postcode": "BH19 2TE", "LONGITUDE": -1.978921, "LATITUDE": 50.6084065}, {"uprn": 100040612353.0, "standardised_address": "22 Steppes, Langton Matravers, Dorset, BH19 3EY", "standardised_postcode": "BH19 3EY", "LONGITUDE": -1.9982872, "LATITUDE": 50.6114398}, {"uprn": 100040615235.0, "standardised_address": "18, FOLLY LANE, WAREHAM, BH20 4HH", "standardised_postcode": "BH20 4HH", "LONGITUDE": -2.1091065, "LATITUDE": 50.6892606}, {"uprn": 100040613496.0, "standardised_address": "11, BELLS ORCHARD LANE, WAREHAM, BH20 4HP", "standardised_postcode": "BH20 4HP", "LONGITUDE": -2.1076971, "LATITUDE": 50.6876586}, {"uprn": 200004818272.0, "standardised_address": "8 CHRISTMAS CLOSE, WAREHAM", "standardised_postcode": "BH20 4RG", "LONGITUDE": -2.1182555, "LATITUDE": 50.6868481}, {"uprn": 10011953366.0, "standardised_address": "3 Long Ground Cottages, Church Knowle", "standardised_postcode": "BH20 5NH", "LONGITUDE": -2.0886006, "LATITUDE": 50.6358618}, {"uprn": 10011953315.0, "standardised_address": "2 Tollgate Cottages, Kimmeridge", "standardised_postcode": "BH20 5PE", "LONGITUDE": -2.1203866, "LATITUDE": 50.6155815}, {"uprn": 200004827674.0, "standardised_address": "5 Hardy Cottages, School Lane, West Lulworth, Dorset, BH20 5SA", "standardised_postcode": "BH20 5SA", "LONGITUDE": -2.2402216, "LATITUDE": 50.6254701}, {"uprn": 100040619240.0, "standardised_address": "43B WEST STREET, BERE REGIS", "standardised_postcode": "BH20 7HS", "LONGITUDE": -2.2223413, "LATITUDE": 50.7545276}, {"uprn": 100041099402.0, "standardised_address": "3 LYS COTTAGES, SOUTHBROOK, BERE REGIS, WAREHAM, BH20 7LH", "standardised_postcode": "BH20 7LH", "LONGITUDE": -2.2180587, "LATITUDE": 50.7499967}, {"uprn": 100040715693.0, "standardised_address": "219, BEAUFORT ROAD, BOURNEMOUTH, BH6 5AF", "standardised_postcode": "BH6 5AF", "LONGITUDE": -1.8032153, "LATITUDE": 50.7350516}, {"uprn": 24102341.0, "standardised_address": "32 MARCONI CLOSE, WESTON-SUPER-MARE", "standardised_postcode": "BS23 3HH", "LONGITUDE": -2.9532424, "LATITUDE": 51.346858}, {"uprn": 539294.0, "standardised_address": "18, CARMARTHEN GROVE, WILLSBRIDGE, BRISTOL, BS30 6UY", "standardised_postcode": "BS30 6UY", "LONGITUDE": -2.477798, "LATITUDE": 51.4318312}, {"uprn": 100041033195.0, "standardised_address": "DORCHESTER YOUTH & COMMUNITY CENTRE, KINGS ROAD, DORCHESTER, DT1 1NJ", "standardised_postcode": "DT1 1NJ", "LONGITUDE": -2.4256275, "LATITUDE": 50.712939}, {"uprn": 100040630187.0, "standardised_address": "35 ALFRED PLACE, DORCHESTER", "standardised_postcode": "DT1 1NW", "LONGITUDE": -2.4289537, "LATITUDE": 50.7124378}, {"uprn": 100040603020.0, "standardised_address": "9 Thrift Close, Stalbridge", "standardised_postcode": "DT10 2LE", "LONGITUDE": -2.371142, "LATITUDE": 50.9560518}, {"uprn": 100040603027.0, "standardised_address": "16, THRIFT CLOSE, STALBRIDGE, STURMINSTER NEWTON, DT10 2LE", "standardised_postcode": "DT10 2LE", "LONGITUDE": -2.3710023, "LATITUDE": 50.9563849}, {"uprn": 10013220368.0, "standardised_address": "16 PORTMAN MEWS, BRYANSTON, BLANDFORD FORUM, DT11 0PR", "standardised_postcode": "DT11 0PR", "LONGITUDE": -2.1854767, "LATITUDE": 50.8609862}, {"uprn": 100040589446.0, "standardised_address": "1 YARDE FARM, PIMPERNE", "standardised_postcode": "DT11 8XF", "LONGITUDE": -2.1359685, "LATITUDE": 50.878473}, {"uprn": 100040589449.0, "standardised_address": "4 YARDE FARM, PIMPERNE", "standardised_postcode": "DT11 8XF", "LONGITUDE": -2.1359404, "LATITUDE": 50.8786079}, {"uprn": 100040589455.0, "standardised_address": "10 YARDE FARM, PIMPERNE", "standardised_postcode": "DT11 8XF", "LONGITUDE": -2.1360556, "LATITUDE": 50.8790934}, {"uprn": 100040588938.0, "standardised_address": "3 PLUMBLEY MEADOWS, WINTERBORNE KINGSTON", "standardised_postcode": "DT11 9BY", "LONGITUDE": -2.1991201, "LATITUDE": 50.7784828}, {"uprn": 100040603895.0, "standardised_address": "5, Woodsford Lane, Moreton", "standardised_postcode": "DT2 8AY", "LONGITUDE": -2.3122792, "LATITUDE": 50.7027633}, {"uprn": 100040640575.0, "standardised_address": "3 WOODBURY DROVE, CROSSWAYS", "standardised_postcode": "DT2 8XT", "LONGITUDE": -2.3343597, "LATITUDE": 50.6988929}, {"uprn": 100040659720.0, "standardised_address": "44, Buddleia Close", "standardised_postcode": "DT3 6SG", "LONGITUDE": -2.4455732, "LATITUDE": 50.6450829}, {"uprn": 100040662263.0, "standardised_address": "138, Corporation Road", "standardised_postcode": "DT4 0LQ", "LONGITUDE": -2.4683463, "LATITUDE": 50.6151519}, {"uprn": 100040662275.0, "standardised_address": "150, Corporation Road", "standardised_postcode": "DT4 0LQ", "LONGITUDE": -2.4681304, "LATITUDE": 50.6149443}, {"uprn": 100040626274.0, "standardised_address": "2 Pitchers, Salwayash, Dorset, DT6 5QS", "standardised_postcode": "DT6 5QS", "LONGITUDE": -2.7730072, "LATITUDE": 50.7662791}, {"uprn": 100040626501.0, "standardised_address": "12, RIVERVALE, BRIDPORT, DT6 5RN", "standardised_postcode": "DT6 5RN", "LONGITUDE": -2.7586317, "LATITUDE": 50.740939}, {"uprn": 100040621177.0, "standardised_address": "54 REDLANDS LANE, BROADWINDSOR", "standardised_postcode": "DT8 3ST", "LONGITUDE": -2.7955262, "LATITUDE": 50.8187693}, {"uprn": 10094240246.0, "standardised_address": "43, Willow Rise, Witheridge", "standardised_postcode": "EX16 8FD", "LONGITUDE": -3.6994066, "LATITUDE": 50.9120479}, {"uprn": 10004844899.0, "standardised_address": "WILTSHIRE HOUSE HOSTEL, 64, EXMOUTH STREET, KINGSHILL, SWINDON, SN1 3PU", "standardised_postcode": "SN1 3PU", "LONGITUDE": -1.7943904, "LATITUDE": 51.5551385}, {"uprn": 10094328457.0, "standardised_address": "ROOM 10, 2, SWINDON FOYER, 17-21, BATH ROAD, OLD TOWN, SWINDON, SN1 4AS", "standardised_postcode": "SN1 4AS", "LONGITUDE": -1.7778769, "LATITUDE": 51.5523398}, {"uprn": 100120980894.0, "standardised_address": "10, WINE STREET, DEVIZES, SN10 1AP", "standardised_postcode": "SN10 1AP", "LONGITUDE": -1.9947743, "LATITUDE": 51.3518889}, {"uprn": 100120977834.0, "standardised_address": "19C, MONDAY MARKET STREET, DEVIZES, SN10 1DN", "standardised_postcode": "SN10 1DN", "LONGITUDE": -1.9921895, "LATITUDE": 51.3520506}, {"uprn": 200001300706.0, "standardised_address": "39, HURRICANE ROAD, BOWERHILL, MELKSHAM, SN12 6SZ", "standardised_postcode": "SN12 6SZ", "LONGITUDE": -2.1236125, "LATITUDE": 51.3578666}, {"uprn": 200001300707.0, "standardised_address": "4, HURRICANE ROAD, BOWERHILL, MELKSHAM, SN12 6SZ", "standardised_postcode": "SN12 6SZ", "LONGITUDE": -2.1248482, "LATITUDE": 51.3580721}, {"uprn": 100121013791.0, "standardised_address": "4, SOUTHMEAD, CHIPPENHAM, SN14 0RU", "standardised_postcode": "SN14 0RU", "LONGITUDE": -2.1380925, "LATITUDE": 51.4540985}, {"uprn": 100121013888.0, "standardised_address": "134, SOUTHMEAD, CHIPPENHAM, SN14 0SB", "standardised_postcode": "SN14 0SB", "LONGITUDE": -2.1339064, "LATITUDE": 51.4547597}, {"uprn": 10010426772.0, "standardised_address": "21, CLIVE PARADE, CRICKLADE ROAD, SWINDON, SN2 1AJ", "standardised_postcode": "SN2 1AJ", "LONGITUDE": -1.7755952, "LATITUDE": 51.5844431}, {"uprn": 100121161218.0, "standardised_address": "44 Tulip Tree Close", "standardised_postcode": "SN2 1RR", "LONGITUDE": -1.782982, "LATITUDE": 51.5790352}, {"uprn": 100121344047.0, "standardised_address": "46, Harber Court, May Close", "standardised_postcode": "SN2 1XD", "LONGITUDE": -1.7793342, "LATITUDE": 51.5772052}, {"uprn": 10004840648.0, "standardised_address": "FLAT 3, 6, CAMDALE PARADE, CRICKLADE ROAD, SWINDON, SN2 8AH", "standardised_postcode": "SN2 8AH", "LONGITUDE": -1.7769189, "LATITUDE": 51.573548}, {"uprn": 10004842231.0, "standardised_address": "4, Huddleston Close", "standardised_postcode": "SN2 8BG", "LONGITUDE": -1.7727817, "LATITUDE": 51.5707465}, {"uprn": 100121141804.0, "standardised_address": "96, LENNOX DRIVE, SWINDON, SN3 3BD", "standardised_postcode": "SN3 3BD", "LONGITUDE": -1.7635782, "LATITUDE": 51.5611407}, {"uprn": 100121345610.0, "standardised_address": "14 BRAIN COURT, BUNCE ROAD, SWINDON, SN3 4QT", "standardised_postcode": "SN3 4QT", "LONGITUDE": -1.7510497, "LATITUDE": 51.5782255}, {"uprn": 100121345614.0, "standardised_address": "18 BRAIN COURT, BUNCE ROAD, SWINDON, SN3 4QT", "standardised_postcode": "SN3 4QT", "LONGITUDE": -1.7510497, "LATITUDE": 51.5782255}, {"uprn": 100121345636.0, "standardised_address": "38 BRAIN COURT, BUNCE ROAD, SWINDON, SN3 4QT", "standardised_postcode": "SN3 4QT", "LONGITUDE": -1.7510497, "LATITUDE": 51.5782255}, {"uprn": 100121345678.0, "standardised_address": "74 BRAIN COURT, BUNCE ROAD, SWINDON, SN3 4QU", "standardised_postcode": "SN3 4QU", "LONGITUDE": -1.7510497, "LATITUDE": 51.5782255}, {"uprn": 100121134536.0, "standardised_address": "6, Goulding Close", "standardised_postcode": "SN3 4QY", "LONGITUDE": -1.7486145, "LATITUDE": 51.5801714}, {"uprn": 10008541709.0, "standardised_address": "44, THORNEY PARK, WROUGHTON, SWINDON, SN4 0QS", "standardised_postcode": "SN4 0QS", "LONGITUDE": -1.7872903, "LATITUDE": 51.5116279}, {"uprn": 10008541885.0, "standardised_address": "100, Thorney Park, Wroughton", "standardised_postcode": "SN4 0QT", "LONGITUDE": -1.789516, "LATITUDE": 51.5108628}, {"uprn": 10008541880.0, "standardised_address": "105, Thorney Park, Wroughton", "standardised_postcode": "SN4 0QT", "LONGITUDE": -1.7888605, "LATITUDE": 51.5108736}, {"uprn": 10008541889.0, "standardised_address": "112, Thorney Park, Wroughton", "standardised_postcode": "SN4 0QT", "LONGITUDE": -1.7878319, "LATITUDE": 51.5108692}, {"uprn": 100121169562.0, "standardised_address": "Flat 15, Windmill Court, Uxbridge Road, Freshbrook, Swindon, SN5 8RT", "standardised_postcode": "SN5 8RT", "LONGITUDE": -1.8418052, "LATITUDE": 51.550096}, {"uprn": 100121169564.0, "standardised_address": "Flat 17, Windmill Court, Uxbridge Road, Freshbrook, Swindon, SN5 8RT", "standardised_postcode": "SN5 8RT", "LONGITUDE": -1.8418052, "LATITUDE": 51.550096}, {"uprn": 100121055967.0, "standardised_address": "93-95, ST. EDMUNDS CHURCH STREET, SALISBURY, SP1 1EQ", "standardised_postcode": "SP1 1EQ", "LONGITUDE": -1.7924578, "LATITUDE": 51.0713354}, {"uprn": 100121044735.0, "standardised_address": "44 Glyndebourne Close", "standardised_postcode": "SP2 9EY", "LONGITUDE": -1.8269895, "LATITUDE": 51.0812824}, {"uprn": 200001120569.0, "standardised_address": "10 COOKS CLOSE, SALISBURY", "standardised_postcode": "SP2 9PS", "LONGITUDE": -1.8317301, "LATITUDE": 51.0888336}, {"uprn": 100121047096.0, "standardised_address": "26, Hops Close, Chilmark", "standardised_postcode": "SP3 5BE", "LONGITUDE": -2.0471076, "LATITUDE": 51.0932517}, {"uprn": 100121046662.0, "standardised_address": "12, Hill Close, Tisbury", "standardised_postcode": "SP3 6TB", "LONGITUDE": -2.0788121, "LATITUDE": 51.0669769}, {"uprn": 100121046667.0, "standardised_address": "23, Hill Close, Tisbury", "standardised_postcode": "SP3 6TB", "LONGITUDE": -2.0786986, "LATITUDE": 51.0671501}, {"uprn": 100121046668.0, "standardised_address": "25, Hill Close, Tisbury", "standardised_postcode": "SP3 6TB", "LONGITUDE": -2.0786213, "LATITUDE": 51.0671395}, {"uprn": 100120987378.0, "standardised_address": "113, HIGH STREET, NETHERAVON, SALISBURY, SP4 9PJ", "standardised_postcode": "SP4 9PJ", "LONGITUDE": -1.7907184, "LATITUDE": 51.2385674}, {"uprn": 100121055592.0, "standardised_address": "40, SPIDERS ISLAND, ALDERBURY, WILTSHIRE, SP5 3BG", "standardised_postcode": "SP5 3BG", "LONGITUDE": -1.7204383, "LATITUDE": 51.0379501}, {"uprn": 100121045369.0, "standardised_address": "11, GRIMSTEAD ROAD, WHADDON, SALISBURY, SP5 3EE", "standardised_postcode": "SP5 3EE", "LONGITUDE": -1.7206544, "LATITUDE": 51.0375909}, {"uprn": 100121045372.0, "standardised_address": "19, Grimstead Road, Whaddon", "standardised_postcode": "SP5 3EE", "LONGITUDE": -1.7204116, "LATITUDE": 51.0376623}, {"uprn": 200002927526.0, "standardised_address": "6, Stanley Close, Bishopstone", "standardised_postcode": "SP5 4BH", "LONGITUDE": -1.9035983, "LATITUDE": 51.0312746}, {"uprn": 10010447328.0, "standardised_address": "17 HILLVIEW, EBBESBOURNE WAKE", "standardised_postcode": "SP5 5JJ", "LONGITUDE": -2.0155382, "LATITUDE": 51.0160085}, {"uprn": 100040690924.0, "standardised_address": "2, Lime Tree Close, Alderholt", "standardised_postcode": "SP6 3RQ", "LONGITUDE": -1.8334067, "LATITUDE": 50.9123707}, {"uprn": 100040900005.0, "standardised_address": "26 TURNER CLOSE, BRIDGWATER", "standardised_postcode": "TA6 3PA", "LONGITUDE": -2.9996053, "LATITUDE": 51.1249647}, {"uprn": 10002989537.0, "standardised_address": "CARTREF, WINNINGS WAY, TORQUAY, TQ1 3GZ", "standardised_postcode": "TQ1 3GZ", "LONGITUDE": -3.513879, "LATITUDE": 50.4785659}, {"uprn": 100061879598.0, "standardised_address": "11 Blackdown Road", "standardised_postcode": "BN13 2EZ", "LONGITUDE": -0.4017112, "LATITUDE": 50.8371451}, {"uprn": 100061879600.0, "standardised_address": "14, BLACKDOWN ROAD, WORTHING, BN13 2EZ", "standardised_postcode": "BN13 2EZ", "LONGITUDE": -0.401944, "LATITUDE": 50.8371204}, {"uprn": 100061899941.0, "standardised_address": "25, QUANTOCK ROAD, WORTHING, BN13 2HQ", "standardised_postcode": "BN13 2HQ", "LONGITUDE": -0.4024977, "LATITUDE": 50.8375507}, {"uprn": 100062191147.0, "standardised_address": "40 Hurst Cottages, East Street, Amberley, Horsham, BN18 9NP", "standardised_postcode": "BN18 9NP", "LONGITUDE": -0.5285661, "LATITUDE": 50.9086612}, {"uprn": 100062191157.0, "standardised_address": "50 Hurst Cottages, East Street, Amberley, Horsham, BN18 9NP", "standardised_postcode": "BN18 9NP", "LONGITUDE": -0.5284547, "LATITUDE": 50.9096733}, {"uprn": 200002880107.0, "standardised_address": "9a Hurst Cottages, East Street, Amberley, Horsham, BN18 9NP", "standardised_postcode": "BN18 9NP", "LONGITUDE": -0.5298463, "LATITUDE": 50.9097002}, {"uprn": 100061911692.0, "standardised_address": "Flat 4, Highland Lodge, 17 Carew Road, Eastbourne, BN21 2JQ", "standardised_postcode": "BN21 2JQ", "LONGITUDE": 0.2759205, "LATITUDE": 50.7765092}, {"uprn": 10010653970.0, "standardised_address": "3 GLADSTONE CLOSE, EASTBOURNE", "standardised_postcode": "BN22 9BP", "LONGITUDE": 0.2792262, "LATITUDE": 50.7975267}, {"uprn": 100061914793.0, "standardised_address": "Flat 2, Lakeside Court, 6 Lakelands Close, Eastbourne, BN22 9EQ", "standardised_postcode": "BN22 9EQ", "LONGITUDE": 0.2878669, "LATITUDE": 50.7989404}, {"uprn": 10010655892.0, "standardised_address": "5, Britten Close", "standardised_postcode": "BN23 7TR", "LONGITUDE": 0.3111695, "LATITUDE": 50.8061167}, {"uprn": 10010655608.0, "standardised_address": "5, Laughton Close", "standardised_postcode": "BN23 8JU", "LONGITUDE": 0.287275, "LATITUDE": 50.8121013}, {"uprn": 100060019188.0, "standardised_address": "23 Rotherfield Avenue", "standardised_postcode": "BN23 8JZ", "LONGITUDE": 0.2887367, "LATITUDE": 50.8109304}, {"uprn": 100061916123.0, "standardised_address": "12 The Rookery, Eastbourne, BN23 8LD", "standardised_postcode": "BN23 8LD", "LONGITUDE": 0.3010123, "LATITUDE": 50.8114353}, {"uprn": 10004614538.0, "standardised_address": "10 BUTTS FIELD, HAILSHAM", "standardised_postcode": "BN27 2BZ", "LONGITUDE": 0.2641057, "LATITUDE": 50.8558489}, {"uprn": 10004614505.0, "standardised_address": "1 BUTTS FIELD, HAILSHAM", "standardised_postcode": "BN27 2BZ", "LONGITUDE": 0.2630997, "LATITUDE": 50.8564551}, {"uprn": 22136962.0, "standardised_address": "16, BLUEBIRD COURT 12-14, HOVE STREET, HOVE, BN3 2TU", "standardised_postcode": "BN3 2TU", "LONGITUDE": -0.1806456, "LATITUDE": 50.826389}, {"uprn": 100062006747.0, "standardised_address": "19 Nelson House, Short Street, Rushmoor, GU11 1HX", "standardised_postcode": "GU11 1HX", "LONGITUDE": -0.7667619, "LATITUDE": 51.2496261}, {"uprn": 100062006748.0, "standardised_address": "20 Nelson House, Short Street, Rushmoor, GU11 1HX", "standardised_postcode": "GU11 1HX", "LONGITUDE": -0.7667619, "LATITUDE": 51.2496261}, {"uprn": 100060533152.0, "standardised_address": "5, Raglan Close", "standardised_postcode": "GU12 4PG", "LONGITUDE": -0.7516103, "LATITUDE": 51.2440431}, {"uprn": 100061765042.0, "standardised_address": "1 RANVILLE CLOSE, PETWORTH", "standardised_postcode": "GU28 0EN", "LONGITUDE": -0.6124007, "LATITUDE": 50.9814381}, {"uprn": 100061762685.0, "standardised_address": "21 JUNE MEADOWS, MIDHURST", "standardised_postcode": "GU29 9ER", "LONGITUDE": -0.7509855, "LATITUDE": 50.9904527}, {"uprn": 100061762706.0, "standardised_address": "42 JUNE MEADOWS, MIDHURST", "standardised_postcode": "GU29 9ER", "LONGITUDE": -0.7517059, "LATITUDE": 50.9906852}, {"uprn": 200001064783.0, "standardised_address": "17 Chestnut Close", "standardised_postcode": "GU29 9TT", "LONGITUDE": -0.7473381, "LATITUDE": 50.9766817}, {"uprn": 200001064789.0, "standardised_address": "2, HORNBEAM WAY, MIDHURST, GU29 9TU", "standardised_postcode": "GU29 9TU", "LONGITUDE": -0.7483841, "LATITUDE": 50.9769806}, {"uprn": 100062161165.0, "standardised_address": "Flat 7, Brook House, Park Drive, Waverley, GU6 7EH", "standardised_postcode": "GU6 7EH", "LONGITUDE": -0.4741177, "LATITUDE": 51.1453322}, {"uprn": 100062367433.0, "standardised_address": "COPTHORNE COTTAGE, BRIGHTON ROAD, KINGSWOOD, TADWORTH, KT20 6BQ", "standardised_postcode": "KT20 6BQ", "LONGITUDE": -0.2205069, "LATITUDE": 51.3005374}, {"uprn": 100062145269.0, "standardised_address": "Flat 1, Copthorne House, Brighton Road, Kingswood, Reigate and Banstead, KT20 6BQ", "standardised_postcode": "KT20 6BQ", "LONGITUDE": -0.2203005, "LATITUDE": 51.3003094}, {"uprn": 100062145274.0, "standardised_address": "Flat 6, Copthorne House, Brighton Road, Kingswood, Reigate and Banstead, KT20 6BQ", "standardised_postcode": "KT20 6BQ", "LONGITUDE": -0.2203005, "LATITUDE": 51.3003094}, {"uprn": 100062145280.0, "standardised_address": "Flat 11, Copthorne House, Brighton Road, Kingswood, Reigate and Banstead, KT20 6BQ", "standardised_postcode": "KT20 6BQ", "LONGITUDE": -0.22026, "LATITUDE": 51.3006146}, {"uprn": 10007059816.0, "standardised_address": "2, OLD ST. MARYS, WEST HORSLEY, LEATHERHEAD, KT24 6JG", "standardised_postcode": "KT24 6JG", "LONGITUDE": -0.4571645, "LATITUDE": 51.2643896}, {"uprn": 100120914390.0, "standardised_address": "42, Wordsworth Road", "standardised_postcode": "OX14 5NX", "LONGITUDE": -1.2998371, "LATITUDE": 51.6633308}, {"uprn": 10011922279.0, "standardised_address": "60, Goldings Road, Hook Norton", "standardised_postcode": "OX15 5FG", "LONGITUDE": -1.4854983, "LATITUDE": 52.0000434}, {"uprn": 200001511761.0, "standardised_address": "78G, PARK STREET, THAME, OX9 3HX", "standardised_postcode": "OX9 3HX", "LONGITUDE": -0.9726332, "LATITUDE": 51.744209}, {"uprn": 100061693227.0, "standardised_address": "65, ESSEX ROAD, BOGNOR REGIS, PO21 2BY", "standardised_postcode": "PO21 2BY", "LONGITUDE": -0.6808471, "LATITUDE": 50.7923111}, {"uprn": 100061699117.0, "standardised_address": "64A, LINDEN ROAD, BOGNOR REGIS, PO21 2DT", "standardised_postcode": "PO21 2DT", "LONGITUDE": -0.6799074, "LATITUDE": 50.7883884}, {"uprn": 100061694176.0, "standardised_address": "22, FLETCHER WAY, BOGNOR REGIS, PO21 2NU", "standardised_postcode": "PO21 2NU", "LONGITUDE": -0.6808653, "LATITUDE": 50.7916638}, {"uprn": 100061694158.0, "standardised_address": "3, FLETCHER WAY, BOGNOR REGIS, PO21 2NU", "standardised_postcode": "PO21 2NU", "LONGITUDE": -0.6814028, "LATITUDE": 50.7922275}, {"uprn": 100061708497.0, "standardised_address": "66A, VICTORIA DRIVE, BOGNOR REGIS, PO21 2TG", "standardised_postcode": "PO21 2TG", "LONGITUDE": -0.6821079, "LATITUDE": 50.7868215}, {"uprn": 100061692981.0, "standardised_address": "7, ELM TREE CLOSE, BOGNOR REGIS, PO21 5BF", "standardised_postcode": "PO21 5BF", "LONGITUDE": -0.6893863, "LATITUDE": 50.7974796}, {"uprn": 100061688879.0, "standardised_address": "32, Birdham Close", "standardised_postcode": "PO21 5TD", "LONGITUDE": -0.6958816, "LATITUDE": 50.7960865}, {"uprn": 100061707577.0, "standardised_address": "32, The Croft", "standardised_postcode": "PO21 5TH", "LONGITUDE": -0.6968881, "LATITUDE": 50.7950995}, {"uprn": 1775024104.0, "standardised_address": "15, EDENBRIDGE ROAD, SOUTHSEA, PO4 8PE", "standardised_postcode": "PO4 8PE", "LONGITUDE": -1.0477756, "LATITUDE": 50.7983904}, {"uprn": 310063074.0, "standardised_address": "2, OPAL COURT, LOWER FIELD ROAD, READING, RG1 6BW", "standardised_postcode": "RG1 6BW", "LONGITUDE": -0.97969, "LATITUDE": 51.4489452}, {"uprn": 310006357.0, "standardised_address": "Flat 1, Galloway House, Rembrandt Way, Reading, RG1 6QU", "standardised_postcode": "RG1 6QU", "LONGITUDE": -0.9915054, "LATITUDE": 51.4449921}, {"uprn": 310056378.0, "standardised_address": "112, ADMIRALS COURT, ROSE KILN LANE, READING, RG1 6SS", "standardised_postcode": "RG1 6SS", "LONGITUDE": -0.9773714, "LATITUDE": 51.4470907}, {"uprn": 200004733000.0, "standardised_address": "Flat 6, Lynton Court, Pelican Lane, West Berkshire, RG14 1NN", "standardised_postcode": "RG14 1NN", "LONGITUDE": -1.3238052, "LATITUDE": 51.4073996}, {"uprn": 200004733014.0, "standardised_address": "Flat 20, Lynton Court, Pelican Lane, West Berkshire, RG14 1NN", "standardised_postcode": "RG14 1NN", "LONGITUDE": -1.3242952, "LATITUDE": 51.4073215}, {"uprn": 10007903996.0, "standardised_address": "11 Donnington Lodge, Oxford Road, Donnington, West Berkshire, RG14 3AA", "standardised_postcode": "RG14 3AA", "LONGITUDE": -1.3286281, "LATITUDE": 51.4177589}, {"uprn": 100081226752.0, "standardised_address": "23 DONNINGTON LODGE, OXFORD ROAD, DONNINGTON, NEWBURY, RG14 3AA", "standardised_postcode": "RG14 3AA", "LONGITUDE": -1.3287324, "LATITUDE": 51.4175077}, {"uprn": 310001598.0, "standardised_address": "14, Hagley Road", "standardised_postcode": "RG2 0DN", "LONGITUDE": -0.9682675, "LATITUDE": 51.4411482}, {"uprn": 310032425.0, "standardised_address": "26, Hagley Road", "standardised_postcode": "RG2 0DN", "LONGITUDE": -0.9686028, "LATITUDE": 51.4409533}, {"uprn": 100080226372.0, "standardised_address": "3, Butts Furlong, Brightwalton", "standardised_postcode": "RG20 7DH", "LONGITUDE": -1.3881378, "LATITUDE": 51.5113557}, {"uprn": 100062458850.0, "standardised_address": "3 DAYS MEADOW, WOOLTON HILL", "standardised_postcode": "RG20 9US", "LONGITUDE": -1.3912259, "LATITUDE": 51.35076}, {"uprn": 100060223249.0, "standardised_address": "9, DANKWORTH ROAD, BASINGSTOKE, RG22 4LJ", "standardised_postcode": "RG22 4LJ", "LONGITUDE": -1.120265, "LATITUDE": 51.2424042}, {"uprn": 100060223353.0, "standardised_address": "133, Dankworth Road", "standardised_postcode": "RG22 4LJ", "LONGITUDE": -1.120787, "LATITUDE": 51.2420754}, {"uprn": 100060225935.0, "standardised_address": "36, Foxs Furlong, Chineham", "standardised_postcode": "RG24 8WN", "LONGITUDE": -1.0443702, "LATITUDE": 51.2967794}, {"uprn": 10001320962.0, "standardised_address": "17, Longs Court", "standardised_postcode": "RG28 7BU", "LONGITUDE": -1.3400448, "LATITUDE": 51.2300347}, {"uprn": 310009363.0, "standardised_address": "38, STRATHY CLOSE, READING, RG30 2PP", "standardised_postcode": "RG30 2PP", "LONGITUDE": -1.0145665, "LATITUDE": 51.4587161}, {"uprn": 310048525.0, "standardised_address": "21, COLLIERS WAY, READING, RG30 2QS", "standardised_postcode": "RG30 2QS", "LONGITUDE": -1.0103715, "LATITUDE": 51.4549271}, {"uprn": 310059914.0, "standardised_address": "42, COLLIERS WAY, READING, RG30 2QT", "standardised_postcode": "RG30 2QT", "LONGITUDE": -1.0103342, "LATITUDE": 51.4553225}, {"uprn": 310008254.0, "standardised_address": "3 Brook Lea, Caversham, Reading, RG4 8EP", "standardised_postcode": "RG4 8EP", "LONGITUDE": -0.9594228, "LATITUDE": 51.464404}, {"uprn": 310040251.0, "standardised_address": "7 Brook Lea, Caversham, Reading, RG4 8EP", "standardised_postcode": "RG4 8EP", "LONGITUDE": -0.9588334, "LATITUDE": 51.4643718}, {"uprn": 100121306362.0, "standardised_address": "4, Smith Close, Sonning Common", "standardised_postcode": "RG4 9TL", "LONGITUDE": -0.9851249, "LATITUDE": 51.5186171}, {"uprn": 14049181.0, "standardised_address": "3, Kendrick Close", "standardised_postcode": "RG40 2LZ", "LONGITUDE": -0.8363485, "LATITUDE": 51.4070013}, {"uprn": 100080247057.0, "standardised_address": "12, The Glebe, Aldworth", "standardised_postcode": "RG8 9SH", "LONGITUDE": -1.1981048, "LATITUDE": 51.5116775}, {"uprn": 100080247061.0, "standardised_address": "17, The Glebe, Aldworth", "standardised_postcode": "RG8 9SH", "LONGITUDE": -1.1985385, "LATITUDE": 51.5115996}, {"uprn": 100061824929.0, "standardised_address": "16, VINALL GARDENS, OLD GUILDFORD ROAD, BROADBRIDGE HEATH, HORSHAM, RH12 3HX", "standardised_postcode": "RH12 3HX", "LONGITUDE": -0.3640146, "LATITUDE": 51.0719231}, {"uprn": 10003085392.0, "standardised_address": "18 St. Marks Lane, Horsham, RH12 5PU", "standardised_postcode": "RH12 5PU", "LONGITUDE": -0.3145139, "LATITUDE": 51.0829412}, {"uprn": 100062482574.0, "standardised_address": "Flat 1, Wigmore House, Keymer Road, Mid Sussex, RH15 0AH", "standardised_postcode": "RH15 0AH", "LONGITUDE": -0.1263008, "LATITUDE": 50.9487666}, {"uprn": 100062483148.0, "standardised_address": "12 OAKENFIELD, BURGESS HILL", "standardised_postcode": "RH15 8SJ", "LONGITUDE": -0.1355338, "LATITUDE": 50.9656152}, {"uprn": 100062483149.0, "standardised_address": "14 OAKENFIELD, BURGESS HILL", "standardised_postcode": "RH15 8SJ", "LONGITUDE": -0.1360491, "LATITUDE": 50.9655873}, {"uprn": 100062483150.0, "standardised_address": "15, Oakenfield", "standardised_postcode": "RH15 8SJ", "LONGITUDE": -0.1361846, "LATITUDE": 50.9655929}, {"uprn": 100061832309.0, "standardised_address": "9B STANE STREET CLOSE, CODMORE HILL, PULBOROUGH", "standardised_postcode": "RH20 1BD", "LONGITUDE": -0.5026947, "LATITUDE": 50.9661759}, {"uprn": 100061831182.0, "standardised_address": "3, Piers Secomb Close, Coldwaltham", "standardised_postcode": "RH20 1QA", "LONGITUDE": -0.5421865, "LATITUDE": 50.9370885}, {"uprn": 100061826991.0, "standardised_address": "57, Beech Grove, Storrington", "standardised_postcode": "RH20 3NP", "LONGITUDE": -0.4416205, "LATITUDE": 50.9245994}, {"uprn": 100062512568.0, "standardised_address": "FLAT 41, KERRIGAN COURT, 16, WESTWOOD ROAD, SOUTHAMPTON, SO17 1JT", "standardised_postcode": "SO17 1JT", "LONGITUDE": -1.4022734, "LATITUDE": 50.9223801}, {"uprn": 100062512088.0, "standardised_address": "FLAT 6, RAGLAN COURT, 11, WINN ROAD, SOUTHAMPTON, SO17 1WU", "standardised_postcode": "SO17 1WU", "LONGITUDE": -1.4025758, "LATITUDE": 50.9243151}, {"uprn": 10034867337.0, "standardised_address": "6a, Epping Close", "standardised_postcode": "SO18 5SE", "LONGITUDE": -1.3526289, "LATITUDE": 50.9247678}, {"uprn": 100060305293.0, "standardised_address": "21, MOUNTBATTEN ROAD, EASTLEIGH, SO50 4RQ", "standardised_postcode": "SO50 4RQ", "LONGITUDE": -1.3550759, "LATITUDE": 50.9819271}, {"uprn": 100061985990.0, "standardised_address": "Flat 10, Raglan Court, Mountbatten Road, Eastleigh, SO50 4RR", "standardised_postcode": "SO50 4RR", "LONGITUDE": -1.3541953, "LATITUDE": 50.9822382}, {"uprn": 200000713806.0, "standardised_address": "2 NUTBANE CLOSE, ANDOVER", "standardised_postcode": "SP10 3WA", "LONGITUDE": -1.5003561, "LATITUDE": 51.2059018}, {"uprn": 100060566549.0, "standardised_address": "9, Vespasian Road", "standardised_postcode": "SP10 5JP", "LONGITUDE": -1.476821, "LATITUDE": 51.2249974}, {"uprn": 100060566550.0, "standardised_address": "10, VESPASIAN ROAD, ANDOVER, SP10 5JP", "standardised_postcode": "SP10 5JP", "LONGITUDE": -1.4767158, "LATITUDE": 51.2254375}, {"uprn": 100060566565.0, "standardised_address": "25, VESPASIAN ROAD, ANDOVER, SP10 5JP", "standardised_postcode": "SP10 5JP", "LONGITUDE": -1.4776377, "LATITUDE": 51.224965}, {"uprn": 100060563379.0, "standardised_address": "52, ROMAN WAY, ANDOVER, SP10 5JU", "standardised_postcode": "SP10 5JU", "LONGITUDE": -1.4764479, "LATITUDE": 51.2250676}, {"uprn": 100060049602.0, "standardised_address": "5, Salisbury Road", "standardised_postcode": "TN37 6RX", "LONGITUDE": 0.5616196, "LATITUDE": 50.862757}]
\ No newline at end of file
diff --git a/etl/customers/stonewater/map_app/assets/hestia-logo.png b/etl/customers/stonewater/map_app/assets/hestia-logo.png
new file mode 100644
index 00000000..8a49c95b
Binary files /dev/null and b/etl/customers/stonewater/map_app/assets/hestia-logo.png differ
diff --git a/etl/customers/stonewater/map_app/assets/osmosis-Logo.svg b/etl/customers/stonewater/map_app/assets/osmosis-Logo.svg
new file mode 100644
index 00000000..d1937f9b
--- /dev/null
+++ b/etl/customers/stonewater/map_app/assets/osmosis-Logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/etl/customers/stonewater/map_app/assets/stonewater-logo.png b/etl/customers/stonewater/map_app/assets/stonewater-logo.png
new file mode 100644
index 00000000..0d05f58f
Binary files /dev/null and b/etl/customers/stonewater/map_app/assets/stonewater-logo.png differ
diff --git a/etl/customers/stonewater/map_app/callbacks.py b/etl/customers/stonewater/map_app/callbacks.py
new file mode 100644
index 00000000..e69de29b
diff --git a/etl/customers/stonewater/map_app/config.py b/etl/customers/stonewater/map_app/config.py
new file mode 100644
index 00000000..1dbd5d04
--- /dev/null
+++ b/etl/customers/stonewater/map_app/config.py
@@ -0,0 +1,8 @@
+import os
+import json
+import dotenv
+
+# When running locally, we'll need to load the .env file
+dotenv.load_dotenv()
+
+MAPBOX_ACCESS_TOKEN = os.getenv("MAPBOX_ACCESS_TOKEN")
diff --git a/etl/customers/stonewater/map_app/map_page.py b/etl/customers/stonewater/map_app/map_page.py
new file mode 100644
index 00000000..bb85961e
--- /dev/null
+++ b/etl/customers/stonewater/map_app/map_page.py
@@ -0,0 +1,230 @@
+import dash_bootstrap_components as dbc
+from dash import html, dcc
+import json
+import plotly.graph_objects as go
+import pandas as pd
+
+from config import MAPBOX_ACCESS_TOKEN
+
+
+def make_real_epc_piechart(real_epc_breakdown):
+ labels = [x["is_real_epc"] for x in real_epc_breakdown]
+ values = [x["count"] for x in real_epc_breakdown]
+
+ marker_colors = ["#027fa6", "rgb(225 225 225)"]
+
+ fig = go.Figure(
+ data=[go.Pie(labels=labels, values=values, marker_colors=marker_colors)],
+ )
+
+ fig.update_layout(margin={"t": 0})
+
+ plot = dcc.Graph(figure=fig, config={"displayModeBar": False})
+
+ return plot
+
+
+def make_epc_rating_piechart(epc_rating_breakdown):
+ # Re-order from G to A
+ epc_rating_breakdown = sorted(epc_rating_breakdown, key=lambda x: x["EPC"])
+
+ labels = [x["EPC"] for x in epc_rating_breakdown]
+ values = [x["count"] for x in epc_rating_breakdown]
+
+ marker_colors = ["#117d58", "#2da55c", "#8dbd40", "#f7cd14", "#f3a96a", "#ef8026", "#e41e3b"]
+
+ fig = go.Figure(
+ data=[go.Pie(labels=labels, values=values, marker_colors=marker_colors, sort=False)],
+ )
+
+ fig.update_layout(margin={"t": 0})
+
+ plot = dcc.Graph(figure=fig, config={"displayModeBar": False})
+
+ return plot
+
+
+def make_map(locations):
+ if not locations:
+ return None
+
+ df = pd.DataFrame(locations)
+
+ # Create custom hover text
+ df['hover_text'] = df.apply(
+ lambda row: f"UPRN: {int(row['uprn'])}
Address: {row['standardised_address']}
Postcode: "
+ f"{row['standardised_postcode']}
Latitude: {row['LATITUDE']}
Longitude: {row['LONGITUDE']}",
+ axis=1)
+
+ data = [
+ go.Scattermapbox(
+ lat=df["LATITUDE"].tolist(),
+ lon=df["LONGITUDE"].tolist(),
+ mode="markers",
+ marker=go.scattermapbox.Marker(size=10, color="#027fa6"),
+ text=df["hover_text"], # Use the custom hover text
+ hoverinfo='text'
+ )
+ ]
+
+ layout = go.Layout(
+ autosize=True,
+ hovermode="closest",
+ mapbox=go.layout.Mapbox(
+ accesstoken=MAPBOX_ACCESS_TOKEN,
+ bearing=0,
+ center=go.layout.mapbox.Center(lat=53, lon=-1.5),
+ pitch=0,
+ zoom=5,
+ ),
+ margin={"t": 0},
+ )
+
+ fig = go.Figure(data=data, layout=layout)
+
+ plot = dcc.Graph(figure=fig, config={"displayModeBar": False})
+
+ return plot
+
+
+def layout():
+ # Get the data
+ with open("Stonewater Mapping Data.json", "r") as file:
+ locations = json.load(file)
+
+ # Get the EPC breakdown data
+ with open("Stonewater real EPC breakdown.json") as file:
+ real_epc_breakdown = json.load(file)
+
+ # Get the EPC ratings data
+ with open("Stonewater EPC rating breakdown.json") as file:
+ epc_rating_breakdown = json.load(file)
+
+ page = dbc.Container(
+ [
+ dbc.Row(
+ dbc.Col(
+ html.Div(
+ [
+ # Banner with logos
+ dbc.Row(
+ [
+ dbc.Col(
+ html.Img(src="assets/stonewater-logo.png", height="50px"),
+ width="auto"
+ ),
+ dbc.Col(
+ html.Img(src="assets/osmosis-Logo.svg", height="50px"),
+ width="auto"
+ ),
+ dbc.Col(
+ html.Div(
+ style={"color": "white", "font-size": "1.5rem", "font-weight": "bold"}
+ ),
+ width=True,
+ className="text-center"
+ )
+ ],
+ className="align-items-center",
+ style={"background-color": "#027fa6", "padding": "10px"}
+ ),
+ dbc.Row(
+ [
+ dbc.Col("Powered by", style={"color": "#027fa6", "fontSize": "1rem", 'zIndex': 10},
+ width="auto"),
+ dbc.Col(
+ html.A(
+ html.Img(src="assets/hestia-logo.png", height="50px"),
+ href="https://hestia.homes",
+ ),
+ width="auto",
+ style={"margin-left": "-60px"}
+ ),
+ ],
+ justify='left',
+ align="center"
+ ),
+ html.H1(
+ "Stonewater Survey Map",
+ style={"font-size": "2.5rem", "font-weight": "bold", "margin-bottom": "20px"}
+ ),
+ html.P(
+ "This map shows the location of the properties that are to be surveyed by Osmosis.",
+ style={"font-size": "1.25rem", "margin-bottom": "40px"}
+ ),
+ ],
+ className="text-center"
+ ),
+ width=12
+ ),
+ className="mt-5"
+ ),
+ dbc.Row(
+ dbc.Col(
+ make_map(locations=locations),
+ width=10,
+ align="center",
+ className="text-center"
+ ),
+ justify="center"
+ ),
+ dbc.Row(
+ [
+ dbc.Col(
+ [
+ html.Div(
+ "Breakdown of real EPCs",
+ style={"fontSize": "1.5rem", "fontWeight": "bold", "marginBottom": "1em"},
+ className='text-center'
+ ),
+ html.Div(
+ "This pie chart shows the proportion of real EPCs in the asset list. Currently, "
+ "there are EPCs for 3736 of the 5245 properties that have a UPRN in the asset list",
+ style={"marginBottom": "1em"}
+ ),
+ make_real_epc_piechart(real_epc_breakdown),
+ ],
+ width={"size": 5},
+ ),
+ dbc.Col(
+ [
+ html.Div(
+ "EPC Ratings for properties with an EPC",
+ style={"fontSize": "1.5rem", "fontWeight": "bold", "marginBottom": "1em"},
+ className='text-center'
+ ),
+ html.Div(
+ [
+ "This pie chart shows the breakdown of EPC ratings, for properties that currently "
+ "have an EPC. "
+ "The ratings range from A to G, where surprisingly, there are two EPC properties "
+ "that were initially "
+ "expected by Parity's modelled SAP, to be EPC D or below. These properties can be"
+ " seen ",
+ html.A("here",
+ href="https://find-energy-certificate.service.gov.uk/energy-certificate"
+ "/2708-5001-7327-6090-7284",
+ target="_blank"),
+ " and ",
+ html.A("here",
+ href="https://find-energy-certificate.service.gov.uk/energy-certificate"
+ "/1037-4032-1009-0361-7292",
+ target="_blank"),
+ "."
+ ],
+ style={"marginBottom": "1em"}
+ ),
+ make_epc_rating_piechart(epc_rating_breakdown),
+ ],
+
+ width={"size": 5},
+ ),
+ ],
+ justify="center"
+ )
+ ],
+ fluid=True,
+ className="p-5"
+ )
+
+ return page
diff --git a/etl/customers/stonewater/map_app/requirements.txt b/etl/customers/stonewater/map_app/requirements.txt
new file mode 100644
index 00000000..81943dd1
--- /dev/null
+++ b/etl/customers/stonewater/map_app/requirements.txt
@@ -0,0 +1,12 @@
+dash==2.8.1
+gunicorn
+pandas
+dash-bootstrap-components==1.3.1
+boto3
+dropbox
+Flask-Caching
+dash-extensions
+mysql-connector-python
+sqlalchemy
+werkzeug==2.3.7
+python-dotenv
\ No newline at end of file
diff --git a/etl/customers/stonewater/map_app/server.py b/etl/customers/stonewater/map_app/server.py
new file mode 100644
index 00000000..87f10e21
--- /dev/null
+++ b/etl/customers/stonewater/map_app/server.py
@@ -0,0 +1,45 @@
+import logging
+import secrets
+
+import dash_bootstrap_components as dbc
+from dash import html
+from dash_extensions.enrich import DashProxy, MultiplexerTransform
+import flask
+from map_page import layout
+
+logger = logging.getLogger(__name__)
+
+# We just use a simple secret key for the moment
+
+SECRET_KEY = secrets.token_hex(24)
+
+
+def init_app():
+ app = DashProxy(
+ __name__,
+ server=flask.Flask(__name__),
+ suppress_callback_exceptions=True,
+ external_stylesheets=[
+ dbc.themes.BOOTSTRAP,
+ dbc.icons.FONT_AWESOME,
+ "https://fonts.googleapis.com/css?family=Comfortaa",
+ ],
+ transforms=[MultiplexerTransform()]
+ )
+
+ server = app.server
+
+ # Set app config
+ server.config.update(
+ SECRET_KEY=SECRET_KEY,
+ )
+
+ app.title = "Hesta X Stonewater"
+
+ # Define the layout
+ app.layout = layout()
+
+ return app
+
+
+app = init_app()
diff --git a/etl/customers/stonewater/map_app/wsgi.py b/etl/customers/stonewater/map_app/wsgi.py
new file mode 100644
index 00000000..3390e6ff
--- /dev/null
+++ b/etl/customers/stonewater/map_app/wsgi.py
@@ -0,0 +1,8 @@
+# Callbacks must be imported to run the app
+import callbacks # NOQA
+from server import app
+
+application = app.server
+
+if __name__ == "__main__":
+ app.run_server(port=8080, debug=True, host="0.0.0.0")
diff --git a/etl/customers/stonewater/outputs 27th June 2024.py b/etl/customers/stonewater/outputs 27th June 2024.py
new file mode 100644
index 00000000..7a78469c
--- /dev/null
+++ b/etl/customers/stonewater/outputs 27th June 2024.py
@@ -0,0 +1,132 @@
+"""
+This script prepares some outputs for the stonewater project, 27th June 2024
+
+The work done so far has been data cleaning and clustering.
+In this script, we do the following things:
+
+1) Match the clustering data to the archetypes
+2) Do some basic analysis on the data
+3) Mapping of the archetypes
+"""
+import pandas as pd
+import json
+from utils.s3 import read_pickle_from_s3
+
+stonewater_asset_list = pd.read_csv("Stonewater asset list with archetypes V2.csv")
+archetyped_asset_list = stonewater_asset_list[
+ [
+ "internal_id", "customer_asset_id", "external_address_id", "udprn", "uprn", "cluster",
+ "archetype_representative", "rank"
+ ]
+].copy()
+archetyped_asset_list = archetyped_asset_list[archetyped_asset_list["rank"] != "NO ARCHETYPE"]
+archetyped_asset_list["rank"] = archetyped_asset_list["rank"].astype(int)
+# Sort
+archetyped_asset_list = archetyped_asset_list.sort_values(by=["cluster", "rank"])
+
+# Read in and merge on clustering features
+clustering_features = read_pickle_from_s3(
+ bucket_name="retrofit-data-dev",
+ s3_file_name="customers/Stonewater/clustering/clustering_dataframe.pkl"
+)
+
+# Move property-type and built-form to the first two columns
+columns_to_move = ['property-type', 'built-form']
+
+# Get the remaining columns
+remaining_columns = [col for col in clustering_features.columns if col not in columns_to_move]
+
+# Create the new column order
+new_column_order = columns_to_move + remaining_columns
+
+# Reorder the DataFrame
+clustering_features = clustering_features[new_column_order]
+
+archetyped_asset_list = archetyped_asset_list.merge(
+ clustering_features,
+ on="internal_id",
+ how="inner"
+)
+
+archetyped_asset_list = archetyped_asset_list.rename(
+ columns={
+ "internal_id": "Osm. ID",
+ "customer_asset_id": "Org. ref.",
+ "external_address_id": "Address ID",
+ "cluster": "Archetype ID",
+ "archetype_representative": "Archetype Representative",
+ "rank": "Archetype Group Rank",
+ }
+)
+archetyped_asset_list["uprn"] = archetyped_asset_list["uprn"].astype('Int64')
+# Create an extract of the features
+
+
+# Look at number of combinations
+# - If we look at the number of combinations of property type & built form, we have 25 unique combinations
+# - If we look at the number of combinations of property type, built form, and walls description, this jumps
+# massively to 237 unique combinations
+# - Adding roof description to the mix, we have 857 unique combinations
+# - Adding floor description, we have 1278 unique combinations
+# This doesn't even begin to consider the other variables that we have in the dataset, such as the property dimensions,
+# location, and other factors.
+# Ideally, we would perfectly separate these variables but this is not possible, given the constraint of needing ~450
+# archetypes. We will need to make some compromises here. This is where a clustering algorithm can help us.
+# We don't end up with perfect separation but we can get a good enough separation to make the archetypes useful, and can
+# base the archetypes on a number of energy performance metrics, as well as location and other factors.
+# archetyped_asset_list[
+# ["property-type", "built-form", "walls-description", "roof-description",
+# "floor-description"]].drop_duplicates().shape
+
+# Save this as an excel
+# archetyped_asset_list.to_excel("Stonewater Archetyping Features.xlsx", index=False)
+
+# We store the location data, which will be used for the mapping. We just need the longitude and latitude
+mapping_data = stonewater_asset_list[
+ stonewater_asset_list["archetype_representative"]
+][["internal_id", "uprn", "standardised_address", "standardised_postcode"]]
+
+mapping_data = mapping_data.merge(
+ clustering_features[["internal_id", "LONGITUDE", "LATITUDE"]],
+)
+mapping_data = mapping_data.drop(columns=["internal_id"])
+
+with open("etl/customers/stonewater/map_app/Stonewater Mapping Data.json", "w") as f:
+ f.write(json.dumps(mapping_data.to_dict(orient="records")))
+
+# We also include some data for visualising the breakdown of EPCS
+proportion_of_real_epcs = clustering_features["estimated"].value_counts().to_frame().reset_index()
+# Invert the true and false
+proportion_of_real_epcs["estimated"] = ~proportion_of_real_epcs["estimated"]
+proportion_of_real_epcs = proportion_of_real_epcs.rename(
+ columns={"estimated": "is_real_epc"}
+)
+
+with open("etl/customers/stonewater/map_app/Stonewater real EPC breakdown.json", "w") as f:
+ f.write(json.dumps(proportion_of_real_epcs.to_dict(orient="records")))
+
+# Produce the breakdown of EPC ratings
+epc_rating_breakdown = (
+ clustering_features[~clustering_features["estimated"]]["current-energy-rating"]
+ .value_counts()
+ .to_frame()
+ .reset_index()
+)
+
+epc_rating_breakdown = epc_rating_breakdown.rename(
+ columns={"current-energy-rating": "EPC"}
+)
+
+with open("etl/customers/stonewater/map_app/Stonewater EPC rating breakdown.json", "w") as f:
+ f.write(json.dumps(epc_rating_breakdown.to_dict(orient="records")))
+
+epc_a_properties = clustering_features[
+ (clustering_features["current-energy-rating"] == "A")
+ & (~clustering_features["estimated"])
+ ]
+
+epc_a_properties = epc_a_properties.merge(
+ stonewater_asset_list,
+ on="internal_id",
+ how="inner"
+)
diff --git a/etl/customers/stonewater/shdf_3_clustering.py b/etl/customers/stonewater/shdf_3_clustering.py
index 6c7a0fc6..bdac5ec2 100644
--- a/etl/customers/stonewater/shdf_3_clustering.py
+++ b/etl/customers/stonewater/shdf_3_clustering.py
@@ -14,6 +14,11 @@ import pandas as pd
import time
from utils.s3 import save_data_to_s3, read_excel_from_s3, read_from_s3, read_dataframe_from_s3_parquet, \
save_dataframe_to_s3_parquet, save_pickle_to_s3
+from sklearn.cluster import KMeans
+from sklearn.preprocessing import StandardScaler, OneHotEncoder
+from sklearn.compose import ColumnTransformer
+from sklearn.pipeline import Pipeline
+from scipy.spatial.distance import cdist
load_dotenv(dotenv_path="backend/.env")
EPC_AUTH_TOKEN = os.getenv("EPC_AUTH_TOKEN")
@@ -673,7 +678,8 @@ def compile_data():
# )[["AddressId", "UDPRN"]].rename(columns={"AddressId": "external_address_id"})
asset_list = pd.read_excel(
- "/Users/khalimconn-kowlessar/Downloads/Stonewater SHDF_3_0_Board Triage 22.05.24.xlsx", header=4
+ "/Users/khalimconn-kowlessar/Documents/hestia/Stonewater/Stonewater SHDF_3_0_Board Triage 22.05.24.xlsx",
+ header=4
)
udprn_data = pd.read_excel(
@@ -1090,6 +1096,26 @@ def concatenate_row(row):
return ', '.join(row.dropna().replace('', None).dropna().astype(str))
+def adjust_clusters(cluster_allocation, total_clusters):
+ current_total = sum(cluster_allocation.values())
+ adjustment = total_clusters - current_total
+ if adjustment > 0:
+ # Increase clusters, start from the largest group
+ for group in sorted(cluster_allocation, key=lambda x: -cluster_allocation[x]):
+ cluster_allocation[group] += 1
+ adjustment -= 1
+ if adjustment == 0:
+ break
+ elif adjustment < 0:
+ # Decrease clusters, start from the largest group
+ for group in sorted(cluster_allocation, key=lambda x: -cluster_allocation[x]):
+ cluster_allocation[group] -= 1
+ adjustment += 1
+ if adjustment == 0:
+ break
+ return cluster_allocation
+
+
def compile_data_final():
# Updated version:
@@ -1103,7 +1129,8 @@ def compile_data_final():
########################################################################
asset_list = pd.read_excel(
- "/Users/khalimconn-kowlessar/Downloads/Stonewater SHDF_3_0_Board Triage 22.05.24.xlsx", header=4
+ "/Users/khalimconn-kowlessar/Documents/hestia/Stonewater/Stonewater SHDF_3_0_Board Triage 22.05.24.xlsx",
+ header=4
)
udprn_data = pd.read_excel(
@@ -1633,124 +1660,243 @@ def compile_data_final():
# )
# from utils.s3 import read_pickle_from_s3
- # data = read_pickle_from_s3(
+ # property_attributes = read_pickle_from_s3(
# bucket_name="retrofit-data-dev",
# s3_file_name="customers/Stonewater/clustering/clustering_dataframe.pkl"
# )
+ # We perform some additional cleaning on the data
+ import msgpack
+ cleaned = read_from_s3(
+ s3_file_name="cleaned_epc_data/cleaned.bson",
+ bucket_name="retrofit-data-dev"
+ )
+
+ cleaned = msgpack.unpackb(cleaned, raw=False)
+ from etl.epc_clean.epc_attributes.FloorAttributes import FloorAttributes
+ from etl.epc_clean.epc_attributes.HotWaterAttributes import HotWaterAttributes
+ from etl.epc_clean.epc_attributes.MainFuelAttributes import MainFuelAttributes
+ from etl.epc_clean.epc_attributes.MainheatAttributes import MainHeatAttributes
+ from etl.epc_clean.epc_attributes.MainheatControlAttributes import MainheatControlAttributes
+ from etl.epc_clean.epc_attributes.RoofAttributes import RoofAttributes
+ from etl.epc_clean.epc_attributes.WallAttributes import WallAttributes
+ from etl.epc_clean.epc_attributes.WindowAttributes import WindowAttributes
+ from etl.epc_clean.epc_attributes.LightingAttributes import LightingAttributes
+
+ cleaners = {
+ "floor-description": FloorAttributes,
+ 'hotwater-description': HotWaterAttributes,
+ 'main-fuel': MainFuelAttributes,
+ 'mainheat-description': MainHeatAttributes,
+ 'mainheatcont-description': MainheatControlAttributes,
+ 'roof-description': RoofAttributes,
+ 'walls-description': WallAttributes,
+ 'windows-description': WindowAttributes,
+ 'lighting-description': LightingAttributes
+ }
+
+ for variable_to_clean in cleaned.keys():
+
+ unique_descriptions = property_attributes[variable_to_clean].unique()
+ clean_df = pd.DataFrame(cleaned[variable_to_clean])
+ # Check if we have any
+ missed = [x for x in unique_descriptions if x not in clean_df["original_description"].values]
+ if missed:
+ descriptions_to_append = []
+ for description in missed:
+ if variable_to_clean == "lighting-description":
+ cln = cleaners[variable_to_clean](description, **{"averages": pd.DataFrame()})
+ else:
+ cln = cleaners[variable_to_clean](description)
+ to_append = {
+ "original_description": description,
+ "clean_description": cln.description.replace("(assumed)", "").rstrip().capitalize(),
+ **cln.process()
+ }
+ descriptions_to_append.append(to_append)
+
+ descriptions_to_append = pd.DataFrame(descriptions_to_append)
+ clean_df = pd.concat([clean_df, descriptions_to_append])
+
+ clean_df = clean_df.rename(
+ columns={
+ "thermal_transmittance": f"{variable_to_clean}_thermal_transmittance",
+ "is_assumed": f"{variable_to_clean}_is_assumed",
+ }
+ )
+
+ if 'thermal_transmittance_unit' in clean_df.columns:
+ clean_df = clean_df.drop(columns=['thermal_transmittance_unit'])
+
+ starting_size = len(property_attributes)
+ property_attributes = property_attributes.merge(
+ clean_df, how="left", left_on=variable_to_clean, right_on="original_description"
+ )
+ if starting_size != property_attributes.shape[0]:
+ raise Exception("something went wrong")
+ property_attributes = property_attributes.drop(columns=["original_description", "clean_description"])
+ # Fill missings
+ for k in clean_df.columns:
+ if k in property_attributes.columns:
+ property_attributes[k] = property_attributes[k].fillna("missing")
+
+ # We group some variables such as thermal transmittance for walls, roof, floors
+ # ranges = {
+ # "< 0.1": (0, 0.1),
+ # "0.1 - 0.3": (0.1, 0.3),
+ # "0.3 - 0.5": (0.3, 0.5),
+ # "0.5 - 0.7": (0.5, 0.7),
+ # "0.9 - 1": (0.9, 1),
+ # "1 - 1.5": (1, 1.5),
+ # "1.5 - 2": (1.5, 2),
+ # "2+": (2, 2.5)
+ # }
+
+ ranges = {
+ "< 0.1": (0, 0.1),
+ "0.1 - 0.3": (0.1, 0.3),
+ "0.3 - 0.5": (0.3, 0.5),
+ "0.5+": (0.5, 2.5),
+ }
+
+ # Generate the lookup table
+ thermal_transmittance_lookup_table = []
+ for i in range(1, 251):
+ value = i / 100
+ for label, (low, high) in ranges.items():
+ if low < value <= high:
+ thermal_transmittance_lookup_table.append({"from": value, "to": label})
+ break
+
+ # Convert to DataFrame for display
+ thermal_transmittance_lookup_table = pd.DataFrame(thermal_transmittance_lookup_table)
+ thermal_transmittance_lookup_table["from"] = thermal_transmittance_lookup_table["from"].astype(str)
+
+ thermal_transmittance_cols = [
+ c for c in property_attributes.columns if "thermal_transmittance" in c and "unit" not in c
+ ]
+ for i, col in enumerate(thermal_transmittance_cols):
+ # Perform the mapping
+ to_col = f"to_{col}"
+ property_attributes[col] = property_attributes[col].astype(str)
+ property_attributes = property_attributes.merge(
+ thermal_transmittance_lookup_table.rename(columns={"to": to_col}),
+ how="left",
+ left_on=col,
+ right_on="from",
+ suffixes=("", f"_{i}")
+ )
+ property_attributes = property_attributes.drop(columns=["from", col])
+ property_attributes[to_col] = property_attributes[to_col].fillna("unknown")
+
+ # Drop the description columns that are the keys in cleaned
+ print("PUT ME BACK!!??")
+ property_attributes = property_attributes.drop(columns=list(cleaned.keys()))
+ # Perform the mapping
+
# CLUSTERING!!
-
- # from sklearn.cluster import KMeans
- # from sklearn.preprocessing import OneHotEncoder
- # from scipy.spatial.distance import cdist
- #
- # property_attributes.set_index('internal_id', inplace=True)
- #
- # # Step 1: Prepare the data
- # # Identify categorical columns (you might need to adjust this)
- # categorical_cols = property_attributes.select_dtypes(include=['object', 'category']).columns.tolist()
- # for col in categorical_cols:
- # property_attributes[col] = property_attributes[col].astype(str)
- #
- # # Applying OneHotEncoder
- # encoder = OneHotEncoder(sparse=False)
- # encoded_cats = encoder.fit_transform(property_attributes[categorical_cols])
- #
- # # Creating a new DataFrame with encoded categorical data and original numerical data
- # numerical_data = property_attributes.select_dtypes(include=[np.number])
- # data_for_clustering = pd.concat([numerical_data, pd.DataFrame(encoded_cats, index=numerical_data.index)], axis=1)
- #
- # # Convert all column names to strings to satisfy KMeans requirements
- # data_for_clustering.columns = data_for_clustering.columns.astype(str)
- #
- # # Step 2: K-Means Clustering
- # k = 450 # number of clusters
- # kmeans = KMeans(n_clusters=k, random_state=0)
- # property_attributes['cluster'] = kmeans.fit_predict(data_for_clustering)
- #
- # # Extracting centroids
- # centroids = kmeans.cluster_centers_
- #
- # # Step 3: Assign clusters and rank rows
- # # Calculating distances from each point to its cluster's centroid
- # distances = cdist(data_for_clustering, centroids, 'euclidean')
- # min_distances = distances.min(axis=1)
- # property_attributes['distance_to_centroid'] = min_distances
- #
- # # Ranking rows by distance within each cluster
- # property_attributes['rank'] = property_attributes.groupby('cluster')['distance_to_centroid'].rank(method='first')
- #
- # # Sorting to verify
- # property_attributes.sort_values(by=['cluster', 'rank'], inplace=True)
- #
- # # Optional: Displaying the dataframe
- # print(property_attributes.head())
-
- from sklearn.cluster import KMeans
- from sklearn.preprocessing import StandardScaler, OneHotEncoder
- from sklearn.compose import ColumnTransformer
- from sklearn.pipeline import Pipeline
- from scipy.spatial.distance import cdist
- id_column = 'internal_id'
- property_attributes.set_index(id_column, inplace=True)
+ grouping_columns = [
+ 'is_cavity_wall', 'is_solid_brick', 'property-type', 'is_pitched', 'is_flat', 'has_dwelling_above'
+ ]
# Define the preprocessing for numerical and categorical features
numerical_features = property_attributes.select_dtypes(include=['int64', 'float64']).columns.tolist()
categorical_features = property_attributes.select_dtypes(include=['object', 'category']).columns.tolist()
+ categorical_features = [c for c in categorical_features if c not in ["internal_id", grouping_columns]]
for col in categorical_features:
property_attributes[col] = property_attributes[col].astype(str)
- preprocessor = ColumnTransformer(
- transformers=[
- ('num', StandardScaler(), numerical_features),
- ('cat', OneHotEncoder(), categorical_features)
+ id_column = 'internal_id'
+ n_clusters = 450
+ random_state = 0
+
+ training_data_grouped = property_attributes.groupby(grouping_columns)
+ group_sizes = {name: len(group) for name, group in training_data_grouped}
+ total_size = sum(group_sizes.values())
+ cluster_allocation = {
+ name: max(1, int(round(n_clusters * (size / total_size)))) for name, size in group_sizes.items()
+ }
+
+ # Adjust cluster allocation to ensure total clusters sum to 450
+ cluster_allocation = adjust_clusters(cluster_allocation, n_clusters)
+
+ # TODO: This code throws many warnings because of the highly fragmented dataframe. We should re-factor this to
+ # collect the results of the clustering and then perform the transformations afterwards
+
+ final_clusters = []
+ for group_variables, group_data in tqdm(training_data_grouped, total=len(training_data_grouped)):
+
+ group_n_clusters = cluster_allocation[group_variables]
+ group_data.set_index(id_column, inplace=True)
+
+ preprocessor = ColumnTransformer(
+ transformers=[
+ ('num', StandardScaler(), numerical_features),
+ ('cat', OneHotEncoder(), categorical_features)
+ ]
+ )
+
+ pipeline = Pipeline(steps=[('preprocessor', preprocessor),
+ ('kmeans', KMeans(n_clusters=group_n_clusters, random_state=random_state))])
+
+ # Fit the pipeline to the data
+ pipeline.fit(group_data)
+
+ # Transform the data using the fitted pipeline
+ processed_data = pipeline.named_steps['preprocessor'].transform(group_data)
+
+ # Get cluster labels
+ group_data['cluster'] = pipeline.named_steps['kmeans'].labels_
+
+ # Get centroids (already in the same transformed space)
+ centroids = pipeline.named_steps['kmeans'].cluster_centers_
+
+ # if the data isn't an array, make it one
+ if not isinstance(processed_data, np.ndarray):
+ processed_data = processed_data.toarray()
+
+ # Calculate distances from each point to the centroid of its cluster
+ distances_to_centroids = [
+ cdist(processed_data[i].reshape(1, -1), centroids[label].reshape(1, -1)).flatten()[0]
+ for i, label in enumerate(group_data['cluster'])
]
- )
- pipeline = Pipeline(steps=[('preprocessor', preprocessor),
- ('kmeans', KMeans(n_clusters=450, random_state=0))])
+ group_data['distance_to_centroid'] = distances_to_centroids
- # Fit the pipeline to the data
- pipeline.fit(property_attributes)
+ # for cluster_id in group_data['cluster'].unique():
+ # cluster_data = group_data[group_data['cluster'] == cluster_id]
+ # min_distance = cluster_data['distance_to_centroid'].min()
+ # print(f"Cluster {cluster_id} minimum distance to centroid: {min_distance}")
+ # if min_distance != 0:
+ # print(f"No point with zero distance found in cluster {cluster_id}")
- # Transform the data using the fitted pipeline
- processed_data = pipeline.named_steps['preprocessor'].transform(property_attributes)
+ # Ranking rows by distance within each cluster
+ group_data['rank'] = group_data.groupby('cluster')['distance_to_centroid'].rank(method='first')
- # Get cluster labels
- property_attributes['cluster'] = pipeline.named_steps['kmeans'].labels_
+ # Sorting to verify
+ group_data.sort_values(by=['cluster', 'rank'], inplace=True)
+ group_data.reset_index(inplace=True)
- # Get centroids (already in the same transformed space)
- centroids = pipeline.named_steps['kmeans'].cluster_centers_
+ to_append = group_data[["internal_id", "cluster", "rank"]].copy()
+ to_append["cluster"] = to_append["cluster"].astype(str) + str(group_variables)
+ final_clusters.append(to_append)
- processed_data = processed_data.toarray()
+ final_clusters = pd.concat(final_clusters)
+ # remap the clusters from the current names to 1 -> n_clusters
- # Calculate distances from each point to the centroid of its cluster
- distances_to_centroids = [
- cdist(processed_data[i].reshape(1, -1), centroids[label].reshape(1, -1)).flatten()[0]
- for i, label in enumerate(property_attributes['cluster'])
- ]
-
- property_attributes['distance_to_centroid'] = distances_to_centroids
-
- for cluster_id in property_attributes['cluster'].unique():
- cluster_data = property_attributes[property_attributes['cluster'] == cluster_id]
- min_distance = cluster_data['distance_to_centroid'].min()
- print(f"Cluster {cluster_id} minimum distance to centroid: {min_distance}")
- if min_distance != 0:
- print(f"No point with zero distance found in cluster {cluster_id}")
-
- # Ranking rows by distance within each cluster
- property_attributes['rank'] = property_attributes.groupby('cluster')['distance_to_centroid'].rank(
- method='first')
-
- # Sorting to verify
- property_attributes.sort_values(by=['cluster', 'rank'], inplace=True)
+ cluster_mapping = {cluster: i for i, cluster in enumerate(final_clusters["cluster"].unique())}
+ final_clusters["cluster"] = final_clusters["cluster"].map(cluster_mapping)
+ final_clusters["cluster"] = final_clusters["cluster"].astype(str)
################################################
# Prepare outputs!!!!
################################################
+
property_attributes.reset_index(inplace=True)
+ property_attributes = property_attributes.merge(
+ final_clusters, how="left", on="internal_id"
+ )
property_attributes["archetype_representative"] = property_attributes["rank"] == 1
asset_list_with_archetypes = asset_list.merge(
@@ -1769,7 +1915,7 @@ def compile_data_final():
asset_list_with_archetypes["archetype_representative"] = asset_list_with_archetypes[
"archetype_representative"].fillna(False)
- asset_list_with_archetypes.to_csv("Stonewater asset list with archetypes.csv", index=False)
+ asset_list_with_archetypes.to_csv("Stonewater asset list with archetypes V2.csv", index=False)
stonewater_uprn_lookup = asset_list_with_archetypes[
["external_address_id", "udprn", "uprn", "match_type", "standardised_address", "standardised_postcode"]
@@ -1777,110 +1923,6 @@ def compile_data_final():
stonewater_uprn_lookup.to_excel("Stonewater uprn lookup table.xlsx")
- ################################################
- # Agglomertive Clustering
- ################################################
-
- # from sklearn.cluster import KMeans, AgglomerativeClustering
- # from sklearn.preprocessing import StandardScaler, OneHotEncoder
- # from sklearn.compose import ColumnTransformer
- # from sklearn.pipeline import Pipeline
- # from scipy.spatial.distance import cdist
- # import numpy as np
- # from collections import Counter
- #
- # id_column = 'internal_id'
- # property_attributes.set_index(id_column, inplace=True)
- #
- # # Define the preprocessing for numerical and categorical features
- # numerical_features = property_attributes.select_dtypes(include=['int64', 'float64']).columns.tolist()
- # categorical_features = property_attributes.select_dtypes(include=['object', 'category']).columns.tolist()
- #
- # for col in categorical_features:
- # property_attributes[col] = property_attributes[col].astype(str)
- #
- # preprocessor = ColumnTransformer(
- # transformers=[
- # ('num', StandardScaler(), numerical_features),
- # ('cat', OneHotEncoder(sparse_output=False), categorical_features)
- # ]
- # )
- #
- # # Function to perform clustering and merge small clusters
- # def cluster_with_min_size(data, preprocessor, n_clusters=10, min_size=5):
- # while True:
- # # Preprocess the data
- # processed_data = preprocessor.fit_transform(data)
- #
- # # Initial clustering
- # clustering = AgglomerativeClustering(n_clusters=n_clusters)
- # labels = clustering.fit_predict(processed_data)
- #
- # # Check cluster sizes
- # cluster_counts = Counter(labels)
- #
- # # Find clusters smaller than min_size
- # small_clusters = {cluster for cluster, count in cluster_counts.items() if count < min_size}
- #
- # if not small_clusters:
- # break
- #
- # # Merge small clusters
- # for cluster in small_clusters:
- # # Find the nearest cluster to merge with
- # cluster_data = processed_data[labels == cluster]
- # other_clusters = [i for i in range(n_clusters) if i not in small_clusters]
- # other_cluster_data = [processed_data[labels == i] for i in other_clusters]
- # other_centroids = np.vstack([data.mean(axis=0) for data in other_cluster_data])
- #
- # distances = cdist(cluster_data, other_centroids).mean(axis=0)
- # closest_cluster = other_clusters[np.argmin(distances)]
- #
- # labels[labels == cluster] = closest_cluster
- #
- # n_clusters -= len(small_clusters)
- #
- # return labels
- #
- # # Perform clustering with minimum size constraint
- # n_clusters = 10
- # min_size = 5
- # property_attributes['cluster'] = cluster_with_min_size(property_attributes, preprocessor, n_clusters, min_size)
- #
- # # Filter out empty clusters
- # valid_clusters = property_attributes['cluster'].unique()
- #
- # # Get centroids for the resulting clusters
- # processed_data = preprocessor.transform(property_attributes.drop(columns=["cluster"]))
- # centroids = np.vstack([processed_data[property_attributes['cluster'] == i].mean(axis=0) for i in valid_clusters])
- #
- # # Calculate distances from each point to the centroid of its cluster
- # distances_to_centroids = [
- # cdist(processed_data[i].reshape(1, -1),
- # centroids[valid_clusters.tolist().index(label)].reshape(1, -1)).flatten()[0]
- # for i, label in enumerate(property_attributes['cluster'])
- # ]
- #
- # property_attributes['distance_to_centroid'] = distances_to_centroids
- #
- # # Verify that at least one point in each cluster has zero distance to the centroid
- # for cluster_id in valid_clusters:
- # cluster_data = property_attributes[property_attributes['cluster'] == cluster_id]
- # min_distance = cluster_data['distance_to_centroid'].min()
- # print(f"Cluster {cluster_id} minimum distance to centroid: {min_distance}")
- # if min_distance != 0:
- # print(f"No point with zero distance found in cluster {cluster_id}")
- #
- # # Rank the distances within each cluster
- # property_attributes['rank_within_cluster'] = property_attributes.groupby('cluster')['distance_to_centroid'] \
- # .rank(method='first')
- #
- # # Reset index to get 'internal_id' back
- # property_attributes.reset_index(inplace=True)
- #
- # # Display the DataFrame
- # print(property_attributes)
-
def pull_ideal_postcodes(missing_uprn_with_udprn):
api_key = "" # Log into the platform the get the API key: https://account.ideal-postcodes.co.uk/
diff --git a/etl/epc_clean/epc_attributes/FloorAttributes.py b/etl/epc_clean/epc_attributes/FloorAttributes.py
index 245a91bc..817c2b43 100644
--- a/etl/epc_clean/epc_attributes/FloorAttributes.py
+++ b/etl/epc_clean/epc_attributes/FloorAttributes.py
@@ -38,7 +38,7 @@ class FloorAttributes(Definitions):
self.description: str = description.lower()
self.nodata = (not description) or (description in self.DATA_ANOMALY_MATCHES) or (
- description in self.OBSERVED_ERRORS)
+ description in self.OBSERVED_ERRORS) or (self.description == "sap05:floor")
# Try and perform a translation, incase it's in welsh
self.translate_welsh_text()
diff --git a/etl/epc_clean/epc_attributes/HotWaterAttributes.py b/etl/epc_clean/epc_attributes/HotWaterAttributes.py
index 54deaa09..f9cec48b 100644
--- a/etl/epc_clean/epc_attributes/HotWaterAttributes.py
+++ b/etl/epc_clean/epc_attributes/HotWaterAttributes.py
@@ -129,7 +129,9 @@ class HotWaterAttributes(Definitions):
def __init__(self, description: str):
self.description: str = clean_description(description.lower()).strip()
- self.nodata = not self.description or description in self.DATA_ANOMALY_MATCHES
+ self.nodata = not self.description or description in self.DATA_ANOMALY_MATCHES or (
+ self.description == "sap05 hot-water"
+ )
translation = self.WELSH_TEXT.get(self.description)
diff --git a/etl/epc_clean/epc_attributes/LightingAttributes.py b/etl/epc_clean/epc_attributes/LightingAttributes.py
index 0fe3db16..18475b2d 100644
--- a/etl/epc_clean/epc_attributes/LightingAttributes.py
+++ b/etl/epc_clean/epc_attributes/LightingAttributes.py
@@ -1,15 +1,18 @@
import re
+from BaseUtility import Definitions
from etl.epc_clean.epc_attributes.attribute_utils import clean_description
from etl.epc_clean.utils import correct_spelling
-class LightingAttributes:
+class LightingAttributes(Definitions):
WELSH_TEXT = {
"goleuadau ynni-isel ym mhob un ogçör mannau gosod": "low energy lighting in all fixed outlets",
"dim goleuadau ynni-isel": "no low energy lighting",
"goleuadau ynni-isel ym mhob un o'r mannau gosod": 'Low energy lighting in all fixed outlets'
}
+ OBSERVED_ERRORS = []
+
def __init__(self, description, averages):
self.description: str = clean_description(description.lower())
@@ -18,6 +21,9 @@ class LightingAttributes:
self.description = correct_spelling(self.description)
self.averages = averages
+ self.nodata = (not description) or (description in self.DATA_ANOMALY_MATCHES) or (
+ description in self.OBSERVED_ERRORS) or (description == "SAP05:Lighting")
+
def welsh_translation_search(self):
"""
For welsh text describing the percentage of low energy lighting, we match the regular
@@ -40,6 +46,9 @@ class LightingAttributes:
description = self.description
+ if self.nodata:
+ return {"low_energy_proportion": None}
+
if 'no low energy lighting' in description:
return {"low_energy_proportion": 0}
diff --git a/etl/epc_clean/epc_attributes/MainheatAttributes.py b/etl/epc_clean/epc_attributes/MainheatAttributes.py
index 9f0931a3..56115dca 100644
--- a/etl/epc_clean/epc_attributes/MainheatAttributes.py
+++ b/etl/epc_clean/epc_attributes/MainheatAttributes.py
@@ -77,7 +77,9 @@ class MainHeatAttributes(Definitions):
self.description: str = clean_description(self.description).strip()
# Remove special characters
- self.nodata = not description or description in self.DATA_ANOMALY_MATCHES
+ self.nodata = not description or description in self.DATA_ANOMALY_MATCHES or (
+ description == "SAP05:Main-Heating"
+ )
translation = self.WELSH_TEXT.get(self.description)
if translation:
@@ -97,11 +99,12 @@ class MainHeatAttributes(Definitions):
self.process_edge_cases()
- if (not description or not any(
- rt in self.description for rt in
- self.HEAT_SYSTEMS + self.FUEL_TYPES + self.DISTRIBUTION_SYSTEMS + self.OTHERS
- ) and not self.is_edge_case):
- raise ValueError('Invalid description')
+ if not self.nodata:
+ if (not description or not any(
+ rt in self.description for rt in
+ self.HEAT_SYSTEMS + self.FUEL_TYPES + self.DISTRIBUTION_SYSTEMS + self.OTHERS
+ ) and not self.is_edge_case):
+ raise ValueError('Invalid description')
def process_edge_cases(self) -> (dict, bool):
"""
diff --git a/etl/epc_clean/epc_attributes/MainheatControlAttributes.py b/etl/epc_clean/epc_attributes/MainheatControlAttributes.py
index 887bdda7..46fff6d8 100644
--- a/etl/epc_clean/epc_attributes/MainheatControlAttributes.py
+++ b/etl/epc_clean/epc_attributes/MainheatControlAttributes.py
@@ -117,7 +117,9 @@ class MainheatControlAttributes(Definitions):
def __init__(self, description: str):
self.description: str = clean_description(description.lower()).strip()
- self.nodata = not self.description or description in self.DATA_ANOMALY_MATCHES
+ self.nodata = not self.description or description in self.DATA_ANOMALY_MATCHES or (
+ description == "SAP05:Main-Heating-Controls"
+ )
translation = self.WELSH_TEXT.get(self.description)
if translation:
diff --git a/etl/epc_clean/epc_attributes/WallAttributes.py b/etl/epc_clean/epc_attributes/WallAttributes.py
index 09eac215..49252552 100644
--- a/etl/epc_clean/epc_attributes/WallAttributes.py
+++ b/etl/epc_clean/epc_attributes/WallAttributes.py
@@ -75,12 +75,19 @@ class WallAttributes(Definitions):
'insulation_thickness', 'external_insulation', 'internal_insulation'
]
+ CORRECTIONS = {
+ "Granite or whin, as built, no insulation (assumed)": "Granite or whinstone, as built, no insulation (assumed)",
+ }
+
def __init__(self, description: str):
"""
:param description: Description of the walls.
"""
self.description: str = description
+ if self.description in self.CORRECTIONS:
+ self.description = self.CORRECTIONS[self.description]
+
self.welsh_translation_search()
self.nodata = not description or description in self.DATA_ANOMALY_MATCHES
diff --git a/etl/epc_clean/epc_attributes/WindowAttributes.py b/etl/epc_clean/epc_attributes/WindowAttributes.py
index 5286fc5a..e9139510 100644
--- a/etl/epc_clean/epc_attributes/WindowAttributes.py
+++ b/etl/epc_clean/epc_attributes/WindowAttributes.py
@@ -38,7 +38,7 @@ class WindowAttributes(Definitions):
# In the case of an empty description, we want to return a dictionary with all values set to False
# and indicate there was no data
- self.nodata = not description or description in self.DATA_ANOMALY_MATCHES
+ self.nodata = not description or description in self.DATA_ANOMALY_MATCHES or description == "SAP05:Windows"
translation = self.WELSH_TEXT.get(self.description)
if translation:
diff --git a/etl/epc_clean/epc_attributes/attribute_utils.py b/etl/epc_clean/epc_attributes/attribute_utils.py
index 60f4653e..a5326207 100644
--- a/etl/epc_clean/epc_attributes/attribute_utils.py
+++ b/etl/epc_clean/epc_attributes/attribute_utils.py
@@ -2,8 +2,8 @@ import re
import string
from typing import Tuple, Union, Dict, List
-THERMAL_TRANSMITTANCE_STR = r"average thermal transmittance (-?\d+(\.\d+)?)\s(w/m\S+k)"
-THERMAL_TRANSMITTANCE_REGEX = re.compile(THERMAL_TRANSMITTANCE_STR)
+THERMAL_TRANSMITTANCE_STR = r"average thermal transmittance\s*[=:-]?\s*(-?\d+(\.\d+)?)\s*[wW]/m\S*[kK]"
+THERMAL_TRANSMITTANCE_REGEX = re.compile(THERMAL_TRANSMITTANCE_STR, re.IGNORECASE)
DOUBLE_SPACE_PATTERN = re.compile(r"\s+")