In [1]:
from pathlib import Path
import json
from functools import reduce
import math
import datetime as dt
import pytz 
from itertools import product
from collections import OrderedDict
import time
import sys

import requests
import numpy as np
import pandas as pd
import geopandas as gpd
import shapely.ops as so

import helpers as hp

%load_ext autoreload
%autoreload 2

Download rent data


In [11]:
url_by_name = {
    'detailed-lodged-bonds.csv': 'https://www.mbie.govt.nz/assets/Data-Files/Tenancy-and-housing/Rental-bond-data/Quarterly/9da3db7a4d/detailed-lodged-bonds.csv',
    'detailed-mean-rents.csv': 'https://www.mbie.govt.nz/assets/Data-Files/Tenancy-and-housing/Rental-bond-data/Quarterly/427a0a5095/detailed-mean-rents.csv',
    'detailed-geo-mean-rents.csv': 'https://www.mbie.govt.nz/assets/Data-Files/Tenancy-and-housing/Rental-bond-data/Quarterly/fcb5839378/detailed-geo-mean-rents.csv',
}

for name, url in url_by_name.items():
    r = requests.get(url)
    if not r.ok:
        print("Failed to get", name)
    else:
        print("Getting and saving", name)
        path = hp.DATA_DIR/'collected'/name
        with path.open('w') as tgt:
            tgt.write(r.text)


Getting and saving detailed-lodged-bonds.csv
Getting and saving detailed-mean-rents.csv
Getting and saving detailed-geo-mean-rents.csv

Prepare rent data


In [12]:
# Reshape and merge all rent data sets

def clean(f, name):
    f = f.copy()
    f = f.rename(columns={
        'SAU': 'au2001',
        'Property_Type': 'property_type',
        'Bedrooms': '#bedrooms'
    })

    # Drop subtotals
    cond = False
    for col in ['au2001', 'property_type', '#bedrooms']:
        cond |= f[col].str.contains('total', case=False)

    f = f[~cond].copy()
    
    # Reshape
    id_vars = ['au2001', 'property_type', '#bedrooms']
    value_vars = [c for c in f.columns if '-' in c]
    f = pd.melt(f, id_vars=id_vars, value_vars=value_vars,
      var_name='quarter', value_name=name)
    
    return f

paths = [
    hp.DATA_DIR/'collected'/'detailed-lodged-bonds.csv',
    hp.DATA_DIR/'collected'/'detailed-mean-rents.csv',
    hp.DATA_DIR/'collected'/'detailed-geo-mean-rents.csv',
]
names = [
    'rent_count', 
    'rent_mean', 
    'rent_geo_mean',
]
frames = []
for path, name in zip(paths, names):
    print(path)
    f = pd.read_csv(path, dtype={'SAU': str})
    frames.append(clean(f, name))
    
f = reduce(lambda x, y: pd.merge(x, y), frames)

# Merge in region data
path = hp.get_path('au2001_csv')
g = pd.read_csv(path, dtype={'au2001': str})
f = f.merge(g)

# Write to file
path = hp.get_path('rents')
f.to_csv(path, index=False)
f[f['rent_count'].notnull()].head()


/home/araichev/affordability_nz/data/collected/detailed-lodged-bonds.csv
/home/araichev/affordability_nz/data/collected/detailed-mean-rents.csv
/home/araichev/affordability_nz/data/collected/detailed-geo-mean-rents.csv
Out[12]:
au2001 property_type #bedrooms quarter rent_count rent_mean rent_geo_mean au_name territory region rental_area
256 500202 Flat or Apartment 1 1995-03-01 8.0 82.0 82.0 Mangonui East Far North District Northland Mangonui/Kaeo
280 500202 Flat or Apartment 1 1996-03-01 5.0 79.0 79.0 Mangonui East Far North District Northland Mangonui/Kaeo
284 500202 House 3 1996-03-01 5.0 123.0 118.0 Mangonui East Far North District Northland Mangonui/Kaeo
314 500202 House 3 1997-06-01 5.0 154.0 152.0 Mangonui East Far North District Northland Mangonui/Kaeo
344 500202 House 3 1998-09-01 7.0 139.0 137.0 Mangonui East Far North District Northland Mangonui/Kaeo

In [13]:
# Print latest 2 quarters
hp.get_latest_quarters(2)


Out[13]:
['2018-09-01', '2018-12-01']

Explore rents


In [14]:
rents = hp.get_data('rents')
print(rents['quarter'].unique())
rents.head()


['1993-03-01' '1993-06-01' '1993-09-01' '1993-12-01' '1994-03-01'
 '1994-06-01' '1994-09-01' '1994-12-01' '1995-03-01' '1995-06-01'
 '1995-09-01' '1995-12-01' '1996-03-01' '1996-06-01' '1996-09-01'
 '1996-12-01' '1997-03-01' '1997-06-01' '1997-09-01' '1997-12-01'
 '1998-03-01' '1998-06-01' '1998-09-01' '1998-12-01' '1999-03-01'
 '1999-06-01' '1999-09-01' '1999-12-01' '2000-03-01' '2000-06-01'
 '2000-09-01' '2000-12-01' '2001-03-01' '2001-06-01' '2001-09-01'
 '2001-12-01' '2002-03-01' '2002-06-01' '2002-09-01' '2002-12-01'
 '2003-03-01' '2003-06-01' '2003-09-01' '2003-12-01' '2004-03-01'
 '2004-06-01' '2004-09-01' '2004-12-01' '2005-03-01' '2005-06-01'
 '2005-09-01' '2005-12-01' '2006-03-01' '2006-06-01' '2006-09-01'
 '2006-12-01' '2007-03-01' '2007-06-01' '2007-09-01' '2007-12-01'
 '2008-03-01' '2008-06-01' '2008-09-01' '2008-12-01' '2009-03-01'
 '2009-06-01' '2009-09-01' '2009-12-01' '2010-03-01' '2010-06-01'
 '2010-09-01' '2010-12-01' '2011-03-01' '2011-06-01' '2011-09-01'
 '2011-12-01' '2012-03-01' '2012-06-01' '2012-09-01' '2012-12-01'
 '2013-03-01' '2013-06-01' '2013-09-01' '2013-12-01' '2014-03-01'
 '2014-06-01' '2014-09-01' '2014-12-01' '2015-03-01' '2015-06-01'
 '2015-09-01' '2015-12-01' '2016-03-01' '2016-06-01' '2016-09-01'
 '2016-12-01' '2017-03-01' '2017-06-01' '2017-09-01' '2017-12-01'
 '2018-03-01' '2018-06-01' '2018-09-01' '2018-12-01']
Out[14]:
au2001 property_type #bedrooms quarter rent_count rent_mean rent_geo_mean au_name territory region rental_area
0 500100 House 2 1993-03-01 NaN NaN NaN Awanui Far North District Northland Rural Far North
1 500100 House 3 1993-03-01 NaN NaN NaN Awanui Far North District Northland Rural Far North
2 500100 House 2 1993-06-01 NaN NaN NaN Awanui Far North District Northland Rural Far North
3 500100 House 3 1993-06-01 NaN NaN NaN Awanui Far North District Northland Rural Far North
4 500100 House 2 1993-09-01 NaN NaN NaN Awanui Far North District Northland Rural Far North

In [15]:
# Slice in time and aggregate 
agg_rents = hp.aggregate_rents(rents, '2018-06-01')
agg_rents.head()


/home/araichev/affordability_nz/py/helpers.py:200: FutureWarning: Interpreting tuple 'by' as a list of keys, rather than a single key. Use 'by=[...]' instead of 'by=(...)'. In the future, a tuple will always mean a single key.
  g = f.groupby(groupby_cols).apply(my_agg).reset_index()
/home/araichev/affordability_nz/py/helpers.py:190: RuntimeWarning: invalid value encountered in double_scalars
  d['rent_count']
Out[15]:
rental_area #bedrooms territory region rent_count rent_mean rent_geo_mean
0 Addington 1 Christchurch City Canterbury 176.0 215.215909 210.847596
1 Addington 2 Christchurch City Canterbury 88.0 323.079545 314.383257
2 Addington 3 Christchurch City Canterbury 64.0 421.828125 415.562506
3 Addington 4 Christchurch City Canterbury 6.0 472.000000 466.000000
4 Addington 5+ Christchurch City Canterbury 0.0 NaN NaN

In [16]:
f = hp.aggregate_rents(rents, '2018-06-01', groupby_cols=('au2001', '#bedrooms'))
cond = f['region'] == 'Auckland'
f[cond]


Out[16]:
au2001 #bedrooms territory region rent_count rent_mean rent_geo_mean
286 505300 1 Rodney District Auckland 0.0 NaN NaN
287 505300 2 Rodney District Auckland 5.0 430.000000 429.000000
288 505300 3 Rodney District Auckland 22.0 439.863636 436.726565
289 505300 4 Rodney District Auckland 12.0 457.250000 456.459393
290 505300 5+ Rodney District Auckland 0.0 NaN NaN
291 505400 1 Rodney District Auckland 0.0 NaN NaN
292 505400 2 Rodney District Auckland 0.0 NaN NaN
293 505400 3 Rodney District Auckland 0.0 NaN NaN
294 505400 4 Rodney District Auckland 0.0 NaN NaN
295 505500 1 Rodney District Auckland 7.0 293.000000 289.000000
296 505500 2 Rodney District Auckland 28.0 428.785714 425.648316
297 505500 3 Rodney District Auckland 58.0 527.206897 524.557070
298 505500 4 Rodney District Auckland 30.0 570.000000 565.235589
299 505500 5+ Rodney District Auckland 0.0 NaN NaN
300 505600 1 Rodney District Auckland 6.0 340.000000 331.000000
301 505600 2 Rodney District Auckland 49.0 475.285714 470.140848
302 505600 3 Rodney District Auckland 52.0 637.807692 623.467525
303 505600 4 Rodney District Auckland 53.0 753.773585 724.939614
304 505600 5+ Rodney District Auckland 12.0 939.500000 900.564823
305 505802 1 Rodney District Auckland 0.0 NaN NaN
306 505802 2 Rodney District Auckland 26.0 467.192308 462.925573
307 505802 3 Rodney District Auckland 73.0 595.082192 590.647379
308 505802 4 Rodney District Auckland 40.0 694.350000 684.733922
309 505802 5+ Rodney District Auckland 7.0 886.000000 879.000000
310 505803 1 Rodney District Auckland 0.0 NaN NaN
311 505803 2 Rodney District Auckland 0.0 NaN NaN
312 505803 3 Rodney District Auckland 0.0 NaN NaN
313 505804 1 Rodney District Auckland 0.0 NaN NaN
314 505804 2 Rodney District Auckland 0.0 NaN NaN
315 505804 3 Rodney District Auckland 5.0 538.000000 533.000000
... ... ... ... ... ... ... ...
1936 525910 4 Franklin District Auckland 56.0 595.589286 560.896041
1937 525910 5+ Franklin District Auckland 0.0 NaN NaN
1938 525921 1 Franklin District Auckland 0.0 NaN NaN
1939 525921 2 Franklin District Auckland 28.0 402.642857 400.929660
1940 525921 3 Franklin District Auckland 90.0 486.455556 484.082136
1941 525921 4 Franklin District Auckland 60.0 557.666667 555.299084
1942 525921 5+ Franklin District Auckland 0.0 NaN NaN
1943 525922 1 Franklin District Auckland 0.0 NaN NaN
1944 525922 2 Franklin District Auckland 22.0 367.227273 364.761858
1945 525922 3 Franklin District Auckland 27.0 476.888889 474.778584
1946 525922 4 Franklin District Auckland 12.0 552.916667 550.852692
1947 525922 5+ Franklin District Auckland 0.0 NaN NaN
1948 526101 1 Franklin District Auckland 0.0 NaN NaN
1949 526101 2 Franklin District Auckland 24.0 373.833333 371.435741
1950 526101 3 Franklin District Auckland 63.0 463.761905 460.703722
1951 526101 4 Franklin District Auckland 28.0 511.500000 507.470196
1952 526101 5+ Franklin District Auckland 0.0 NaN NaN
1953 526102 2 Franklin District Auckland 0.0 NaN NaN
1954 526102 3 Franklin District Auckland 12.0 466.000000 464.206850
1955 526102 4 Franklin District Auckland 0.0 NaN NaN
1956 526200 1 Franklin District Auckland 0.0 NaN NaN
1957 526200 2 Franklin District Auckland 10.0 382.500000 377.559267
1958 526200 3 Franklin District Auckland 75.0 443.600000 441.620082
1959 526200 4 Franklin District Auckland 35.0 489.628571 488.064100
1960 526200 5+ Franklin District Auckland 0.0 NaN NaN
1976 526701 1 Franklin District Auckland 0.0 NaN NaN
1977 526701 2 Franklin District Auckland 0.0 NaN NaN
1978 526701 3 Franklin District Auckland 10.0 508.000000 500.497752
1979 526701 4 Franklin District Auckland 0.0 NaN NaN
1980 526701 5+ Franklin District Auckland 0.0 NaN NaN

1680 rows × 7 columns


In [17]:
# What fraction of rental data do we have by #bedrooms?

def hits(group):
    d = {}
    d['hit_frac'] = group['rent_mean'].count()/group['rent_mean'].shape[0]
    return pd.Series(d)

date = '2018-06-01'
f = hp.aggregate_rents(rents, date, groupby_cols=('au2001', '#bedrooms'))
cond = f['region'] == 'Auckland'
print('census area units')
print(f[cond].copy().groupby('#bedrooms').apply(hits).reset_index())

f = hp.aggregate_rents(rents, date, groupby_cols=('rental_area', '#bedrooms'))
cond = f['region'] == 'Auckland'
print('rental area units')
print(f[cond].copy().groupby('#bedrooms').apply(hits).reset_index())


census area units
  #bedrooms  hit_frac
0         1  0.340557
1         2  0.650289
2         3  0.863248
3         4  0.536023
4        5+  0.127796
rental area units
  #bedrooms  hit_frac
0         1  0.696970
1         2  0.959596
2         3  1.000000
3         4  0.838384
4        5+  0.282828

Select latest two quarters and slice into regional chunks


In [18]:
# Get latest two quarters of rents
start_date = hp.get_latest_quarters(2)[0]
rents = hp.get_data('rents')
rents = rents[rents['quarter'] >= start_date].copy()

# Create regional slices
for region in hp.REGIONS:
    # Build rents
    region_c = region.capitalize()
    region_rents = rents[rents['region'] == region_c].copy()
    print(region, region_rents['quarter'].unique(), '#rows =', region_rents.shape[0])
    path = hp.get_path('rents', region)
    print('  Saving to', path)
    
    # Create region directory if it does not exist
    if not path.parent.exists():
        path.parent.mkdir()
        
    region_rents.to_csv(path, index=False)


auckland ['2018-09-01' '2018-12-01'] #rows = 5600
  Saving to /home/araichev/affordability_nz/data/processed/auckland/rents.csv
canterbury ['2018-09-01' '2018-12-01'] #rows = 2542
  Saving to /home/araichev/affordability_nz/data/processed/canterbury/rents.csv
wellington ['2018-09-01' '2018-12-01'] #rows = 2420
  Saving to /home/araichev/affordability_nz/data/processed/wellington/rents.csv

JSONize regional rents for the web, grouping by rental area and number of bedrooms


In [19]:
for region in hp.REGIONS:
    region_rents = hp.get_data('rents', region)
    d = hp.build_json_rents(region_rents)
    path = hp.get_path('rents_json', region)
    print('**', region, '\n', d)
    with path.open('w') as tgt:
        json.dump(d, tgt)


** auckland 
 {'Albany': {'1': 304.0, '2': 505.0, '3': 587.0, '4': 710.0}, 'Avondale': {'1': 247.0, '2': 436.0, '3': 545.0, '4': 552.0}, 'Balmoral': {'1': 338.0, '2': 498.0, '3': 712.0, '4': 771.0}, 'Beachhaven/Birkdale': {'1': None, '2': 464.0, '3': 564.0, '4': 593.0}, 'Blockhouse Bay/New Windsor': {'1': 238.0, '2': 501.0, '3': 555.0, '4': 672.0}, 'Botony Downs': {'1': None, '2': 465.0, '3': 597.0, '4': 689.0}, 'Browns Bay': {'1': 408.0, '2': 493.0, '3': 607.0, '4': 693.0}, 'Bucklands Beach': {'1': None, '2': 564.0, '3': 630.0, '4': 777.0}, 'Central East': {'1': 396.0, '2': 544.0, '3': 785.0, '4': None}, 'Central West': {'1': 397.0, '2': 514.0, '3': 687.0, '4': None}, 'Chatswood/Birkenhead/Northcote Point': {'1': 359.0, '2': 490.0, '3': 645.0, '4': 685.0}, 'Dannemora': {'1': None, '2': 509.0, '3': 627.0, '4': 696.0}, 'Devonport': {'1': 449.0, '2': 513.0, '3': 747.0, '4': 916.0}, 'East Coast Bays': {'1': None, '2': 532.0, '3': 685.0, '4': 785.0}, 'Eden Terrace': {'1': 441.0, '2': 585.0, '3': 646.0, '4': None}, 'Ellerslie': {'1': 423.0, '2': 487.0, '3': 629.0, '4': 701.0}, 'Epsom': {'1': 275.0, '2': 533.0, '3': 777.0, '4': 880.0}, 'Glen Eden': {'1': None, '2': 432.0, '3': 501.0, '4': 591.0}, 'Glen Innes/Pt England/Wai O Taiki': {'1': None, '2': None, '3': 577.0, '4': None}, 'Glendene': {'1': None, '2': 409.0, '3': 497.0, '4': None}, 'Glendhu/Glenfield': {'1': None, '2': 483.0, '3': 572.0, '4': 652.0}, 'Greenhithe/Unsworth Heights': {'1': 450.0, '2': 503.0, '3': 617.0, '4': 772.0}, 'Grey Lynn/Arch Hill': {'1': 376.0, '2': 639.0, '3': 814.0, '4': 934.0}, 'Gulf Harbour': {'1': None, '2': 436.0, '3': 526.0, '4': 586.0}, 'Half Moon Bay/Farm Cove': {'1': None, '2': 460.0, '3': 556.0, '4': 665.0}, 'Harbourside': {'1': 352.0, '2': 687.0, '3': 828.0, '4': None}, 'Henderson': {'1': None, '2': 437.0, '3': 505.0, '4': 624.0}, 'Herne Bay/St Marys': {'1': 436.0, '2': 639.0, '3': 1015.0, '4': None}, 'Highland Park': {'1': None, '2': 471.0, '3': 582.0, '4': 630.0}, 'Hillcrest/Northcote': {'1': 377.0, '2': 480.0, '3': 594.0, '4': 674.0}, 'Hillsborough': {'1': 386.0, '2': 463.0, '3': 597.0, '4': 669.0}, 'Howick': {'1': None, '2': 467.0, '3': 573.0, '4': 675.0}, 'Kelston': {'1': 327.0, '2': 387.0, '3': 500.0, '4': 610.0}, 'Kingsland': {'1': 428.0, '2': 557.0, '3': 726.0, '4': None}, 'Kohimarama': {'1': None, '2': 545.0, '3': 706.0, '4': 1073.0}, 'Lynfield': {'1': None, '2': 466.0, '3': 578.0, '4': 684.0}, 'Mangere': {'1': None, '2': 420.0, '3': 510.0, '4': 647.0}, 'Mangere Bridge/Airport': {'1': 344.0, '2': None, '3': 575.0, '4': None}, 'Mangere East': {'1': 292.0, '2': 423.0, '3': 491.0, '4': None}, 'Manukau Central': {'1': 354.0, '2': 474.0, '3': 543.0, '4': None}, 'Manukau Heights and Manurewa Heights': {'1': None, '2': 463.0, '3': 561.0, '4': 660.0}, 'Manurewa North': {'1': 348.0, '2': 430.0, '3': 507.0, '4': 574.0}, 'Maraetai/Clevedon': {'1': 390.0, '2': 466.0, '3': 605.0, '4': 718.0}, 'Massey/Royal Heights': {'1': None, '2': 193.0, '3': 501.0, '4': 572.0}, 'Meadowbank': {'1': 404.0, '2': 527.0, '3': 706.0, '4': 863.0}, 'Mission Bay/Orakei': {'1': 377.0, '2': 584.0, '3': 784.0, '4': 996.0}, 'Mt Albert/Owairaka': {'1': 289.0, '2': 471.0, '3': 625.0, '4': 753.0}, 'Mt Eden': {'1': 397.0, '2': 516.0, '3': 735.0, '4': 895.0}, 'Mt Roskill/Wesley': {'1': None, '2': 493.0, '3': 573.0, '4': None}, 'Mt Wellington': {'1': None, '2': 465.0, '3': 574.0, '4': 667.0}, 'Mt Wellington North': {'1': 318.0, '2': 461.0, '3': 591.0, '4': None}, 'New Lynn': {'1': 325.0, '2': 437.0, '3': 529.0, '4': 617.0}, 'Newmarket': {'1': 434.0, '2': 560.0, '3': 759.0, '4': None}, 'Newton/Grafton': {'1': 364.0, '2': 586.0, '3': 574.0, '4': None}, 'North Harbour/Pine Hill': {'1': 276.0, '2': 495.0, '3': 623.0, '4': 747.0}, 'Onehunga/Oranga/Te Papapa': {'1': 302.0, '2': 485.0, '3': 605.0, '4': 797.0}, 'Orewa/Whangaparaoa': {'1': 373.0, '2': 462.0, '3': 560.0, '4': 721.0}, 'Otahuhu': {'1': 260.0, '2': 430.0, '3': 493.0, '4': 600.0}, 'Otara': {'1': 253.0, '2': 436.0, '3': 502.0, '4': None}, 'Pakuranga': {'1': None, '2': 447.0, '3': 560.0, '4': 627.0}, 'Panmure': {'1': 338.0, '2': 467.0, '3': 555.0, '4': None}, 'Papakura/Drury/Karaka': {'1': 251.0, '2': 418.0, '3': 489.0, '4': 628.0}, 'Papatoetoe North': {'1': 332.0, '2': 458.0, '3': 555.0, '4': None}, 'Papatoetoe South': {'1': 300.0, '2': 445.0, '3': 546.0, '4': 623.0}, 'Papatoetoe West': {'1': None, '2': 444.0, '3': 541.0, '4': None}, 'Parnell': {'1': 470.0, '2': 685.0, '3': 880.0, '4': None}, 'Penrose/Mt Wellington South': {'1': 264.0, '2': 447.0, '3': 560.0, '4': 622.0}, 'Ponsonby/Freemans Bay': {'1': 496.0, '2': 667.0, '3': 893.0, '4': 1125.0}, 'Pt Chevalier': {'1': 284.0, '2': 566.0, '3': 702.0, '4': None}, 'Pukekohe/Tuakau': {'1': 328.0, '2': 394.0, '3': 467.0, '4': 549.0}, 'Ranui': {'1': None, '2': 417.0, '3': 468.0, '4': 590.0}, 'Remuera': {'1': 374.0, '2': 611.0, '3': 810.0, '4': 1001.0}, 'Remuera South/Meadowbank South': {'1': 373.0, '2': 496.0, '3': 697.0, '4': 845.0}, 'Rewiti/Kumeu/Riverhead': {'1': 331.0, '2': 491.0, '3': 628.0, '4': 709.0}, 'Rothesay/Murrays/Mairangi Bays': {'1': None, '2': 513.0, '3': 664.0, '4': 755.0}, 'Royal Oak/One Tree Hill': {'1': 325.0, '2': 532.0, '3': 648.0, '4': 812.0}, 'Rural Franklin': {'1': None, '2': None, '3': 475.0, '4': 598.0}, 'St Helliers/Glendowie': {'1': None, '2': 570.0, '3': 773.0, '4': 1053.0}, 'St Johns': {'1': 335.0, '2': 519.0, '3': 688.0, '4': 876.0}, 'St Lukes/Sandringham': {'1': 425.0, '2': 485.0, '3': 623.0, '4': 810.0}, 'Sunnynook/Westlake': {'1': None, '2': 517.0, '3': 623.0, '4': 740.0}, 'Takanini/Ardmore': {'1': 355.0, '2': None, '3': 521.0, '4': 621.0}, 'Takapuna': {'1': 492.0, '2': 578.0, '3': 707.0, '4': 965.0}, 'Te Atatu': {'1': None, '2': 423.0, '3': 514.0, '4': 564.0}, 'Te Atatu Peninsula': {'1': None, '2': 463.0, '3': 558.0, '4': 646.0}, 'Three Kings': {'1': 423.0, '2': None, '3': 629.0, '4': 714.0}, 'Titirangi': {'1': None, '2': 445.0, '3': 530.0, '4': None}, 'Torbay': {'1': 371.0, '2': 483.0, '3': 596.0, '4': 738.0}, 'Waiheke Island': {'1': 382.0, '2': 489.0, '3': 602.0, '4': 758.0}, 'Wairau Park/Glenfield North': {'1': None, '2': 447.0, '3': 579.0, '4': 664.0}, 'Waiuku': {'1': None, '2': 384.0, '3': 454.0, '4': 513.0}, 'Waterview/Avondale Heights': {'1': 268.0, '2': 472.0, '3': 586.0, '4': 713.0}, 'Wattle Downs/Conifer Grove': {'1': None, '2': 432.0, '3': 537.0, '4': 607.0}, 'Wellsford/Warkworth/Helensville': {'1': None, '2': 431.0, '3': 475.0, '4': 517.0}, 'West Harbour': {'1': None, '2': 554.0, '3': 601.0, '4': 734.0}, 'Western Beaches/Rural': {'1': None, '2': 434.0, '3': 521.0, '4': 619.0}, 'Western Springs/Morningside': {'1': 397.0, '2': 454.0, '3': 627.0, '4': 785.0}, 'Westmere/Surrey Crescent': {'1': 303.0, '2': 605.0, '3': 775.0, '4': 1150.0}, 'Weymouth': {'1': None, '2': None, '3': 516.0, '4': 580.0}}
** canterbury 
 {'Addington': {'1': 210.0, '2': 314.0, '3': 403.0, '4': 466.0}, 'Aranui/Bromley/Bexley': {'1': None, '2': None, '3': 357.0, '4': None}, 'Ashburton': {'1': 226.0, '2': 297.0, '3': 344.0, '4': 425.0}, 'Avon Loop/Christchurch East': {'1': 258.0, '2': 375.0, '3': 417.0, '4': None}, 'Avonhead/Yaldhurst': {'1': 158.0, '2': 364.0, '3': 425.0, '4': 473.0}, 'Banks Peninsula/Selwyn': {'1': None, '2': 385.0, '3': 424.0, '4': 504.0}, 'Bishopdale/Papanui': {'1': 213.0, '2': 350.0, '3': 427.0, '4': 452.0}, 'Burnside/Harewood': {'1': None, '2': None, '3': 435.0, '4': 497.0}, 'Burwood/Dallington/Avondale': {'1': None, '2': 355.0, '3': 401.0, '4': 449.0}, 'Christchurch Central/Hagley': {'1': 317.0, '2': 431.0, '3': 502.0, '4': None}, 'Fendalton/Strowan/Bryndwr': {'1': 190.0, '2': 420.0, '3': 473.0, '4': 588.0}, 'Halswell/Wigram': {'1': 191.0, '2': 382.0, '3': 462.0, '4': 569.0}, 'Hillmorton/Hoon Hay': {'1': None, '2': None, '3': 404.0, '4': 452.0}, 'Horby/Islington/Hei Hei': {'1': None, '2': 328.0, '3': 415.0, '4': None}, 'Ilam/Westburn': {'1': 150.0, '2': 358.0, '3': 441.0, '4': 536.0}, 'Kaikoura/Hurunui': {'1': None, '2': None, '3': 353.0, '4': None}, 'Linwood/Phillipstown': {'1': 216.0, '2': 297.0, '3': 391.0, '4': 415.0}, 'MacKenzie/Waimate': {'1': 188.0, '2': 224.0, '3': 283.0, '4': None}, 'Marshland/Redwood': {'1': None, '2': None, '3': 421.0, '4': 497.0}, 'Merivale/St Albans West': {'1': 218.0, '2': 360.0, '3': 487.0, '4': 567.0}, 'North Beach/New Brighton/Southshore': {'1': 150.0, '2': 336.0, '3': 390.0, '4': 444.0}, 'Rangiora/Kaiapoi': {'1': None, '2': 322.0, '3': 391.0, '4': 478.0}, 'Redcliffs/Sumner': {'1': 366.0, '2': 386.0, '3': 454.0, '4': 457.0}, 'Riccarton': {'1': 207.0, '2': 358.0, '3': 423.0, '4': 493.0}, 'Richmond/Avonside': {'1': 176.0, '2': 316.0, '3': 390.0, '4': None}, 'Richmond/Shirley': {'1': None, '2': 329.0, '3': 412.0, '4': None}, 'Rural Timaru/Temuka/Geraldine': {'1': None, '2': None, '3': 331.0, '4': None}, 'Rural Waimakariri': {'1': None, '2': None, '3': 439.0, '4': 437.0}, 'Sawyers Arms/Northcote/Belfast': {'1': None, '2': 349.0, '3': 417.0, '4': 580.0}, 'Sockburn/Upper Riccarton': {'1': 187.0, '2': 363.0, '3': 396.0, '4': 419.0}, 'Spreydon/Somerfield': {'1': 167.0, '2': 345.0, '3': 413.0, '4': 459.0}, 'St Albans East/Edgeware': {'1': 204.0, '2': 328.0, '3': 448.0, '4': 471.0}, 'St Albans North/ Mairehau': {'1': None, '2': 332.0, '3': 459.0, '4': 523.0}, 'St Martins/Beckenham/Huntsbury': {'1': None, '2': 287.0, '3': 444.0, '4': None}, 'Styx/Parklands': {'1': None, '2': None, '3': 415.0, '4': 508.0}, 'Sydenham/Waltham': {'1': 193.0, '2': 318.0, '3': 394.0, '4': None}, 'Timaru Township': {'1': 210.0, '2': 255.0, '3': 353.0, '4': 390.0}, 'Waitaki': {'1': 149.0, '2': 270.0, '3': 308.0, '4': None}, 'Westmorland/Cashmere/Barrington': {'1': None, '2': 391.0, '3': 427.0, '4': 539.0}, 'Woolston/Opawa': {'1': 155.0, '2': 315.0, '3': 392.0, '4': 478.0}}
** wellington 
 {'Brooklyn': {'1': 275.0, '2': 467.0, '3': 626.0, '4': 795.0}, 'Carterton/South Wairarapa': {'1': None, '2': 318.0, '3': 374.0, '4': None}, 'Eastern Bays': {'1': None, '2': None, '3': 587.0, '4': 698.0}, 'Epuni/Avalon': {'1': 196.0, '2': 444.0, '3': 530.0, '4': None}, 'Hataitai': {'1': 346.0, '2': 455.0, '3': 672.0, '4': 728.0}, 'Heretaunga/Silverstream': {'1': None, '2': 328.0, '3': 480.0, '4': None}, 'Hutt Central/Waterloo': {'1': 294.0, '2': 433.0, '3': 568.0, '4': 724.0}, 'Island Bay/Melrose': {'1': 202.0, '2': 476.0, '3': 660.0, '4': None}, 'Johnsonville/Newlands': {'1': 207.0, '2': 431.0, '3': 530.0, '4': 678.0}, 'Karori': {'1': None, '2': 521.0, '3': 585.0, '4': 750.0}, 'Karori South/Makara': {'1': None, '2': 476.0, '3': 534.0, '4': None}, 'Kelburn/Aro Valley': {'1': 334.0, '2': 493.0, '3': 682.0, '4': 929.0}, 'Khandallah': {'1': 341.0, '2': None, '3': 726.0, '4': 805.0}, 'Kilbirnie/Lyall Bay': {'1': 301.0, '2': 466.0, '3': 621.0, '4': None}, 'Kingston/Happy Valley': {'1': None, '2': 363.0, '3': 501.0, '4': None}, 'Lambton': {'1': 306.0, '2': 568.0, '3': 682.0, '4': None}, 'Masterton': {'1': None, '2': 253.0, '3': 345.0, '4': 370.0}, 'Miramar/Strathmore': {'1': 400.0, '2': 480.0, '3': 621.0, '4': None}, 'Moera/Waiwhetu': {'1': 247.0, '2': None, '3': 419.0, '4': None}, 'Mt Cook': {'1': 272.0, '2': 526.0, '3': 633.0, '4': 699.0}, 'Mt Victoria/Roseneath': {'1': 321.0, '2': 558.0, '3': 583.0, '4': 585.0}, 'Ngaio/Kaiwharawhara/Wilton': {'1': 353.0, '2': 422.0, '3': 590.0, '4': None}, 'Northland': {'1': 326.0, '2': 469.0, '3': 588.0, '4': 801.0}, 'Oriental Bay/Seatoun': {'1': None, '2': 614.0, '3': 706.0, '4': 903.0}, 'Papakowhai/Whitby/Pauatahanui': {'1': None, '2': None, '3': 559.0, '4': 658.0}, 'Paramata/Mana/Pukerua Bay': {'1': None, '2': None, '3': 500.0, '4': None}, 'Paraparaumu/Raumati': {'1': 198.0, '2': 393.0, '3': 450.0, '4': 517.0}, 'Petone West/Alicetown': {'1': None, '2': 367.0, '3': 562.0, '4': None}, 'Petone/Esplanade': {'1': 271.0, '2': 477.0, '3': 551.0, '4': 692.0}, 'Porirua East/Waitangirua': {'1': None, '2': None, '3': 390.0, '4': None}, 'Stokes Valley': {'1': None, '2': 345.0, '3': 458.0, '4': None}, 'Taita/Naenae': {'1': 223.0, '2': 399.0, '3': 451.0, '4': None}, 'Tawa/Grenada North': {'1': 211.0, '2': 414.0, '3': 486.0, '4': 583.0}, 'Te Aro': {'1': 384.0, '2': 548.0, '3': 682.0, '4': 890.0}, 'Titahi Bay/Onepoto/Elsdon': {'1': 238.0, '2': 434.0, '3': 413.0, '4': None}, 'Totara Park/Maoribank/Te Marua': {'1': None, '2': 352.0, '3': 468.0, '4': None}, 'Trentham North/Wallaceville': {'1': None, '2': 330.0, '3': None, '4': None}, 'Trentham West/Eldersley/Clouston Park': {'1': 183.0, '2': 342.0, '3': 499.0, '4': None}, 'Vogeltown/Berhampore/Newtown': {'1': 301.0, '2': 458.0, '3': 610.0, '4': 760.0}, 'Wadestown/Thordon': {'1': 388.0, '2': 564.0, '3': 666.0, '4': None}, 'Waikanae/Otaki': {'1': 218.0, '2': 359.0, '3': 406.0, '4': 478.0}, 'Wainuiomata': {'1': None, '2': None, '3': 422.0, '4': None}, 'Western Hills/Haywards': {'1': 247.0, '2': 371.0, '3': 507.0, '4': None}}

In [ ]: