Pay My Future First

Today is pay day. Ever since I got my first job, I always “paid my future first.” In other words, at least part of my paycheck was automatically deposited into one kind of savings account or another, only to be touched when making a long-term purchase after allowing the money to grow for a number of years. This day of age, paying your future first is pretty easy — automatic deposits and automatic investing can withdraw money from the account where your direct deposit goes in, and it’s like the money never existed — except it does and it’s being saved. This not only accumulates over time, it also takes advantage of cost averaging — your buying into the market both in low-cost and high-cost times.

As I’ve gotten older, made a little more money, gotten promotions and the alike, I’ve increased the amount I’ve been doing to “pay my future first”. Normally if I get a raise, a cost of living adjustment, or a bigger tax break, I always put the majority of increased funds towards “paying my future first”. Sure I like having a little more money to spend, but I figure I am mostly content with my life now and no need to blow the money — when I can invest it and have more later on, compounded by interest and growth in the markets.

I’ve also diversified where I “pay my future first” money to. Diversity is a good thing because it ensures if any one investment doesn’t work out, there is another one to fall back on. If one goes down, one other is likely to go up. Some are tax-advantaged, like my ordinary IRA deferred compensation for retirement, while others like my Roth IRA are not tax-advantaged, at least not until I retire and take money out of that account.

Some of my investments are very stable but have very modest returns, like my FDIC-insured savings account, or the FDIC certificate of deposits. Some are mid-term investment accounts — things that are maybe have some substantial short-term risk but are investment vehicles that will grow at the rate of the market growth. The later will help me down the road in 10 or 15 years when I go to buy land and my off-grid cabin. I stay away from anything flashy or anything that I isn’t inherently diversified and is not easy to understand.

This has been a fairly successful strategy for me in the past. I paid for both my truck and the lift kit on my truck with cash, just withdrawing money from savings. By not paying interest, I saved quite a bit of money — especially when you consider the compounding nature of interest and depreciation. Likewise, by commuting to college, living at home, taking off time and saving money by avoiding costs however possible, I was able to avoid that trap known as college debt that is negatively impacting so many young adults these days.

Based on my long-range projections of investment and interest, I am really hopeful to be in a place to buy land and be able to move out of New York by the early 2030s (which sounds like a long ways off, but that’s really only about a decade away). The year may slightly change based on the growth of economy and recessions, but I think I have a plan for success. My goals are modest — an off-grid cabin, less then 1,000 feet with maybe 100 acres of land in wilderness — but I think given time I can make it a reality. Land is a lot more affordable in other states, especially if you don’t want a big fancy house, and are content to live in a small town and make less money going forward. But if I own land debt-free, don’t have monthly utility bills or fees, I can be quite rich without a big salary each month.

Working PANDAS and American Community Survey Summary File

Want to be able to work with American Community Survey data offline using your own local copy of the ACS 5-year Summary File? It’s pretty easy to do with PANDAS. If you are planning a lot of Census queries, this can be a very fast way to extract data.

Before you can use this script, you will need to download some data:

import pandas as pd

path = '/home/andy/Desktop/acs-summary-file/'

# list of geography
geo = pd.read_excel(path+'5_year_Mini_Geo.xlsx', sheet_name='ny',index_col='Logical Record Number')

# load headers
header = pd.read_excel(path+'ACS_5yr_Seq_Table_Number_Lookup.xlsx')

# create a column with census variable headers
header['COL_NAME'] = header['Table ID'] + '_' + header['Line Number'].apply(lambda a: "{0:.0f}".format(a).zfill(3))

# segment id, along with ACS year and state
segId = 135
year = 2019
state = 'ny'

# create a list of headers for segment file
segHead = ['FILEID','FILETYPE','STUSAB','CHARITER','SEQUENCE','LOGRECNO'] \
    + header.query('`Sequence Number` == '+str(segId)).dropna(subset=['Line Number'])['COL_NAME'].to_list()

# read the segment file, including column names above    
seg = pd.read_csv(path+'e'+str(year)+'5'+state+(str(segId).zfill(4))+'000.txt',header=None, names=segHead, index_col=5)

# join the segment file to geography using Logical Record number
seg = geo.join(seg)

# calculate percentage of households with internet subscriptions -- codes from ACS_5yr_Seq_Table_Number_Lookup.xlsx
seg['Internet Subscription']=seg['B28011_002']/seg['B28011_001']*100

# output the percentage of households by county with internet subscriptions
seg[seg['Geography ID'].str.startswith('050')][['Geography Name','Internet Subscription']]

Geography NameInternet Subscription
Logical Record Number
13Albany County, New York83.888889
14Allegany County, New York76.248050
15Bronx County, New York75.917821
16Broome County, New York82.222562
17Cattaraugus County, New York72.431480
70Washington County, New York80.224036
71Wayne County, New York81.508715
72Westchester County, New York86.371288
73Wyoming County, New York78.387887
74Yates County, New York75.916583
# alternatively you can display human readable columns automatically
seg.rename(dict(zip(header['COL_NAME'],header['Table Title'])),axis=1)
StateGeography IDGeography NameFILEIDFILETYPESTUSABCHARITERSEQUENCETotal:Has one or more types of computing devices:
Logical Record Number
1NY04000US36New YorkACSSF201900000.0ny0.0135.07343234.06581493.0
2NY04001US36New York — UrbanACSSF201900000.0ny0.0135.06433524.05771681.0
3NY04043US36New York — RuralACSSF201900000.0ny0.0135.0909710.0809812.0
4NY040A0US36New York — In metropolitan or micropolitan st…ACSSF201900000.0ny0.0135.07189902.06449723.0
5NY040C0US36New York — In metropolitan statistical areaACSSF201900000.0ny0.0135.06796057.06109882.0
28400NY97000US3631920Yonkers City School District, New YorkACSSF201900000.0ny0.0135.074897.065767.0
28401NY97000US3631950York Central School District, New YorkACSSF201900000.0ny0.0135.02116.01964.0
28402NY97000US3631980Yorktown Central School District, New YorkACSSF201900000.0ny0.0135.07068.06751.0
28403NY97000US3632010Cuba-Rushford Central School District, New YorkACSSF201900000.0ny0.0135.02629.02186.0
28404NY97000US3699999Remainder of New York, New YorkACSSF201900000.0ny0.0135.079779.075425.0

Too much work or don’t want to download the summary file yourself? You can query the Census API directly using PyPI’s censusdata library from PIP. For infrequent queries where you are online, for those with Internet at home, you would be much better off just querying the API directly.

import pandas as pd
import censusdata as cd

# attributes to load
cdcol=['B28011_001','B28011_002']

cdf = cd.download('acs5', 2019,
           cd.censusgeo([('state', '36'),
                         ('county','*')]),
          cdcol)


# seperate out the geoid and geography name
geoid=[]
geoname=[]

for index in cdf.index.tolist():
    geopart=''
    for part in index.geo:
        geopart = geopart + part[1]
    geoid.append(geopart)
    geoname.append(index.name)

cdf['geoid']=geoid
cdf['geoname']=geoname

# calculate percentage with internet subscriptions
cdf['Internet Subscription']=cdf['B28011_002']/cdf['B28011_001']*100

# output a similar table as above
cdf

Learn how to load into PANDAS the PL 94-171 2020 Redistricting Data, a process that is similar but different then ACS data.

Also, calculate the population of an area and it’s average demographics, including areas that don’t have Census demographics such as Election Districts or County Legislative districts.

I wish the night was nice enough to spend in the wilderness β›Ί

Another rainy April weekend is upon us. At the beginning of the week I really had hope that the state budget would get done and I could head up north for a long weekend on Thursday night. But somehow it didn’t work out that way.

I need a good night in the wilderness next to the fire to restore my sleep. Black flies are certain to be out by next week, which already looks to be rainy. Plus who knows how long the budget process gets dragged out. Too late to do Stoney Pond in the off season in Madison County though I doubt this early in May getting a free online reservation would be difficult.