<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Mike Jarrett (Posts about bikes)</title><link>https://notes.mikejarrett.ca/</link><description></description><atom:link href="https://notes.mikejarrett.ca/categories/bikes.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2025 &lt;a href="mailto:mike@mikejarrett.ca"&gt;Mike Jarrett&lt;/a&gt; </copyright><lastBuildDate>Fri, 29 Aug 2025 20:46:30 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Tracking bikeshare use using GBFS feeds</title><link>https://notes.mikejarrett.ca/tracking-bikeshare-use-using-gbfs-feeds/</link><dc:creator>Mike Jarrett</dc:creator><description>&lt;figure&gt;&lt;img src="https://notes.mikejarrett.ca/images/logo.png"&gt;&lt;/figure&gt; &lt;div class="cell border-box-sizing text_cell rendered"&gt;&lt;div class="prompt input_prompt"&gt;
&lt;/div&gt;&lt;div class="inner_cell"&gt;
&lt;div class="text_cell_render border-box-sizing rendered_html"&gt;
&lt;p&gt;The &lt;a href="https://github.com/NABSA/gbfs"&gt;General Bikeshare Feed Specification (GBFS)&lt;/a&gt; is a popular standard for publishing live data about bikeshare systems used by systems &lt;a href="https://github.com/NABSA/gbfs/blob/master/systems.csv"&gt;around the globe&lt;/a&gt;. Its stated purpose is to allow 3rd party applications to interface with the live data and allow municipalities to monitor compliance with local regulations. For my purpose, it also allows me to monitor system usage in real time. Here I'll go through the steps I use to track bikeshare usage in real time using GBFS feeds. I currently publish live tracking of Vancouver bikeshare systems at &lt;a href="http://twitter.com/vanbikesharebot"&gt;@VanBikeShareBot&lt;/a&gt; and will soon be adding tracking of Toronto, Hamilton and Montreal systems.&lt;/p&gt;
&lt;p&gt;I've bundled the tools I use for GBFS monitoring into a python package that can be &lt;a href="https://github.com/mjarrett/bikedata"&gt;found on Github&lt;/a&gt;. The Bikedata package is not a full-service GBFS client -- for that, you might prefer &lt;a href="https://pypi.org/project/gbfs-client/"&gt;GBFS-client&lt;/a&gt;. Bikedata provides minimal functionality for querying GBFS feeds and returning Pandas dataframes, and implements some helper functions for persistent monitoring of bikeshare systems.&lt;/p&gt;
&lt;h3 id="The-GBFS-spec"&gt;The GBFS spec&lt;a class="anchor-link" href="https://notes.mikejarrett.ca/tracking-bikeshare-use-using-gbfs-feeds/#The-GBFS-spec"&gt;¶&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;I won't go into detail about the GBFS spec, more information can be found on the project's &lt;a href="https://github.com/NABSA/gbfs"&gt;Github page&lt;/a&gt;. Suffice to say that a GBFS complient system offers several distinct JSON endpoints that provide information about the system. For example, Mobi Bikes in Vancouver provides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vancouver-gbfs.smoove.pro/gbfs/gbfs.json"&gt;https://vancouver-gbfs.smoove.pro/gbfs/gbfs.json&lt;/a&gt;: A list of available feeds&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vancouver-gbfs.smoove.pro/gbfs/en/system_information.json"&gt;https://vancouver-gbfs.smoove.pro/gbfs/en/system_information.json&lt;/a&gt;: General system information&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vancouver-gbfs.smoove.pro/gbfs/en/station_information.json"&gt;https://vancouver-gbfs.smoove.pro/gbfs/en/station_information.json&lt;/a&gt;: Details about stations (short and long names, location, coordinates)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vancouver-gbfs.smoove.pro/gbfs/en/station_status.json"&gt;https://vancouver-gbfs.smoove.pro/gbfs/en/station_status.json&lt;/a&gt;: Live status of stations (bikes available, free docks)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mobi doesn't have free floating bikes, but systems that do also have a &lt;code&gt;free_bikes.json&lt;/code&gt; feed providing the location of available free floating bikes.&lt;/p&gt;
&lt;h3 id="Tracking-station-based-systems"&gt;Tracking station-based systems&lt;a class="anchor-link" href="https://notes.mikejarrett.ca/tracking-bikeshare-use-using-gbfs-feeds/#Tracking-station-based-systems"&gt;¶&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Many bikeshare systems, especially those in dense city centres, only allow trips to begin and end at physical stations. To monitor these systems, I periodically query the &lt;code&gt;station_status.json&lt;/code&gt; and record the number of bikes at each station. If the number of available bikes decreases by N, I count that as N departures from the station. If it increases by M, I count that as M bikes returned.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://notes.mikejarrett.ca/tracking-bikeshare-use-using-gbfs-feeds/"&gt;Read more…&lt;/a&gt; (37 min remaining to read)&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description><category>bikes</category><category>mobi</category><guid>https://notes.mikejarrett.ca/tracking-bikeshare-use-using-gbfs-feeds/</guid><pubDate>Mon, 20 Jan 2020 01:12:56 GMT</pubDate></item><item><title>How Vancouver Uses Mobi Bikes</title><link>https://notes.mikejarrett.ca/how-vancouver-uses-mobi-bikes/</link><dc:creator>Mike Jarrett</dc:creator><description>&lt;div class="cell border-box-sizing text_cell rendered"&gt;&lt;div class="prompt input_prompt"&gt;
&lt;/div&gt;&lt;div class="inner_cell"&gt;
&lt;div class="text_cell_render border-box-sizing rendered_html"&gt;
&lt;p&gt;Vancouver's Mobi bikeshare system has been up and running for over 2 years now, and with two full summers of activity it's time to take a look at how exactly Vancouverites are using their bikeshare system.&lt;/p&gt;
&lt;p&gt;For over a year, I've been collecting real-time data about Mobi bike trips by monitoring public information about the number of bikes at each station and inferring trip activity based on changes to the number of bikes at each station. This has led to some fun uses: I have live figures updating constantly on &lt;a href="https://notes.mikejarrett.ca/how-vancouver-uses-mobi-bikes/data.mikejarrett.ca/mobi"&gt;my website&lt;/a&gt;, a twitter bot tweets out daily stats at &lt;a href="https://notes.mikejarrett.ca/how-vancouver-uses-mobi-bikes/twitter.com/VanBikeShareBot"&gt;@VanBikeShareBot&lt;/a&gt;, and a few &lt;a href="http://notes.mikejarrett.ca/categories/mobi/"&gt;blog posts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As handy as those live trip estimates are, they're very much estimates and only give us information about how often certain stations are used. Luckily, Mobi has started publishing open &lt;a href="https://www.mobibikes.ca/en/system-data"&gt;system data&lt;/a&gt;. This data set gives us a registry of every Mobi bikeshare trip since the beginning of 2017, current to the end of 2018 as of this writing. With this we have access to trip start and endpoints, trip duration and distance, membership type and more. In this post, I'll summarize some of the things I've learned after spending some time looking into this data.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://notes.mikejarrett.ca/how-vancouver-uses-mobi-bikes/"&gt;Read more…&lt;/a&gt; (214 min remaining to read)&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description><category>bikes</category><category>datavis</category><category>mobi</category><guid>https://notes.mikejarrett.ca/how-vancouver-uses-mobi-bikes/</guid><pubDate>Mon, 07 Jan 2019 02:27:37 GMT</pubDate></item><item><title>What really affects bikeshare use in Vancouver?</title><link>https://notes.mikejarrett.ca/what-really-affects-bikeshare-use-in-vancouver/</link><dc:creator>Mike Jarrett</dc:creator><description>&lt;p&gt;City staff recently reported to Council about the status of the Mobi bikeshare system. You can see the slideshow for yourself &lt;a href="http://council.vancouver.ca/20171115/documents/cfsc3presentation.pdf"&gt;here&lt;/a&gt;. Results generally look positive for the future of bikeshare in Vancouver, but a comment one slide stuck out for me: "Temperature influences ridership more than precipitation".

Is this really true? In my experience, biking on a cool, dry day is much more enjoyable than biking on a warm rainy day. There was no clue in the council report on how they came to this conclusion, but I suspect they used the eyeball test. But the cooler months in Vancouver are also the rainy months, so a more careful analysis is needed. I'd recently seen an example in Jake Vanderplas' &lt;a href="https://github.com/jakevdp/PythonDataScienceHandbook"&gt;Python Data Science Handbook&lt;/a&gt; that looked at the factors influencing bike ridership in Seattle, so I decided to do a similar thing for Vancouver.

&lt;!--more--&gt;

I've described at bit more about how I collected the Mobi trip data in a &lt;a href="http://mikejarrett.ca/blog/2017/10/machine-learning-with-vancouver-bike-share-data/"&gt;previous post&lt;/a&gt;. While the data is unofficial and has some clear sources of error, it should be reliable to look at usage trends. For weather data, I wrote a small scraper to grab historical Vancouver weather from weather.gc.ca. All the code I used for this post is available on &lt;a href="https://github.com/mjarrett/mobi"&gt;my github page&lt;/a&gt;.

First, let's take a zoomed out look at bike usage from late April to early November 2017. Rainfall and daily highs are plotted on the same scale, in degrees Celcius and millimeters of rain. Weekends are highlighted by grey bars. The first thing we see is the obvious broad trend across the seasons, matching up with the temperature trend. This is probably what city staff noticed. Next, we see that on days with sharp drop-offs from the broader trend, there's almost always some rainfall. So far so good!

&lt;img class="alignnone size-full wp-image-255" src="https://notes.mikejarrett.ca/images/weather_plot_2017-04-20-2017-11-03.png" alt="" width="640" height="480"&gt;

 

(Days with missing data are days I had computer downtime before I moved my scraper to a cloud server.)

A few things to note. Weather data is per day, and for just one Vancouver weather station. There are certainly days where it pours overnight and the day is clear, or it rains more in one part of the city than another. That said, let's take a closer look at a few weeks.

&lt;img class="alignnone size-full wp-image-253" src="https://notes.mikejarrett.ca/images/weather_plot_2017-06-02-2017-06-21.png" alt="" width="640" height="480"&gt;

Here's two consecutive weekends where there was substantial rain on Sunday but none on Saturday. The drop-off is clear on both weekends. But later in the second week, there is a day with much less rainfall that has almost the same drop-off in number of trips.

&lt;img class="alignnone size-full wp-image-254" src="https://notes.mikejarrett.ca/images/weather_plot_2017-09-01-2017-09-21.png" alt="" width="640" height="480"&gt;

Here's another three week stretch. Again, days with rain clearly show reduced Mobi usage. But usage also follows the temperature line! How much of the variation in bike usage is due to temperature, and how much is due to rain?

First let's look at temperature and rainfall separately.

&lt;img class="alignnone size-full wp-image-269" src="https://notes.mikejarrett.ca/images/trips_vs_temp.png" alt="" width="640" height="480"&gt;

The relationship between temperature and bike share trips is strong and exactly what you'd expect. More people ride on warm days! I've coloured the data by rainfall to see if there's any interesting outliers, but the rainy days are all well within the trend. We had pretty great weather all summer this year, so no examples of really rainy days with warm temperatures.

&lt;img class="alignnone size-full wp-image-235" style="font-size: 1rem;" src="https://notes.mikejarrett.ca/images/trips_vs_rainfall.png" alt="" width="640" height="480"&gt;

Rainfall also shows a clear relationship with daily trips. But it's not linear like temperature. There's a band of zero rain days that correlate with temperature, then a linear segment as ridership falls off with increased rainfall, then ridership hits a baseline below which it doesn't decrease. Apparently regardless of the amount of rain there's something like 600-800 users who will take out a bike no matter what. Cool!

So, we need to make a model that incorporates both temperature and rainfall to try to separate their effects. But to be as accurate as possible, we should include any other prominent factors. I showed in a earlier post that over the course of a day, weekdays and weekends show different ridership patters. But it turns out there's no obvious difference in the total number of trips.

&lt;img class="alignnone size-full wp-image-241" style="font-size: 1rem;" src="https://notes.mikejarrett.ca/images/weekdays_vs_weekends_boxplot.png" alt="" width="640" height="480"&gt;

If we're going to think about weekday vs weekend, let's just include each day of the week as a separate factor. Stat holiday vs not holiday should also be included. Since there's such a dramatic difference between days with any rain and days with no rain, let's include "dry" days as a factor. The last factor I'll include is hours of daylight -- when it gets dark before 5pm, it's hard to say whether it's the temperature or the darkness that has more on an effect someone's decision to ride a Mobi.

&lt;code&gt;Trips ~ Temperature + Rainfall + Dry + Holiday + Daylight + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday&lt;/code&gt;

To fit the model, I'll use the OLS (ordinary least squares) class from the statsmodels Python package.
&lt;/p&gt;&lt;pre&gt;                            OLS Regression Results                            
==============================================================================
Dep. Variable:                  Trips       R-squared:                       0.812
Model:                            OLS          Adj. R-squared:                  0.801
Method:                 Least Squares  F-statistic:                     69.65
Date:                Tue, 21 Nov 2017   Prob (F-statistic):           2.49e-58
Time:                        13:57:32           Log-Likelihood:                -1376.9
No. Observations:                 189    AIC:                             2778.
Df Residuals:                     177          BIC:                             2817.
Df Model:                          11                                         
Covariance Type:            nonrobust                                         
================================================================================
                                    coef    std err          t      P&amp;gt;|t|      [0.025      0.975]
--------------------------------------------------------------------------------
Max Temp           117.3302      8.079     14.522      0.000     101.386     133.274
Total Rainmm   -29.8730      6.715     -4.449      0.000     -43.124     -16.622
Mon                     -523.1535    209.4     -2.498      0.013    -936.401    -109.906
Tue                      -523.9437    206.4     -2.537      0.012    -931.439    -116.448
Wed                    -497.6093    209.4     -2.376      0.019    -910.967     -84.252
Thu                     -429.2738    213.2     -2.013      0.046    -850.082      -8.465
Fri                       -368.8536    207.5     -1.777      0.077    -778.440      40.733
Sat                       -487.4666    206.5     -2.360      0.019    -895.072     -79.861
Sun                      -755.6349    207.6     -3.640      0.000   -1165.364    -345.906
Dry                      362.8911     75.665      4.796      0.000     213.569     512.214
Holiday               -277.1649    181.6     -1.526      0.129    -635.701      81.371
daylight_hrs       37.2471       15.672      2.377      0.019       6.319      68.175
==============================================================================
Omnibus:                        9.879   Durbin-Watson:                 1.087
Prob(Omnibus):             0.007   Jarque-Bera (JB):               20.264
Skew:                                0.116   Prob(JB):                             3.98e-05
Kurtosis:                          4.587   Cond. No.                            472.
==============================================================================


&lt;/pre&gt;
We can take a few things away from this table. The adjusted R&lt;sup&gt;2 &lt;/sup&gt;value is 0.801 which means our model explains about 80% of the variance in the data. Pretty good! We can also say that, all other things being equal, there will be
&lt;ul&gt;
    &lt;li&gt;117 more trips for each increase of one degree Celcius&lt;/li&gt;
    &lt;li&gt;30 fewer trips for each additional of 1 mm of rain&lt;/li&gt;
    &lt;li&gt;277 fewer trips on holidays versus equivalent non-holidays&lt;/li&gt;
    &lt;li&gt;37 more trips for each additional hour of daylight&lt;/li&gt;
&lt;/ul&gt;
The coefficients associated with the days of the week can be interpreted as the intercept for each day of the week, in other words the number of trips expected on that day if all other factors are zero. This is obviously nonsense, since we can't have fewer than zero trips. But the daily high temperature for the dates I have data for are all well above zero, so the model doesn't have any data for temperatures near zero. More on this later.

Given our model, we can plot the expected number of trips for each day on top of the measured number of trip.

&lt;img class="alignnone size-full wp-image-248" src="https://notes.mikejarrett.ca/images/trip_vs_predicted_full_model.png" alt="" width="640" height="480"&gt;

The model nails the macroscopic structure, driven by temperature and daylight, and does pretty well with the day-to-day variations which are probably more driven by rainfall and the day of the week.

There's a few big misses, though. Let's look at the days where our model misses the mark by over 1000 trips:

On July 11th, a Tuesday, our model expects a normal summer day but the counted number of trips drops of precipitously. The weather data for that says 20 degrees and no rain, so I'm not sure what's going on. I've looked at my source data and don't see anything out of the ordinary, but I suspect there was a data acquisition issue that day.

On August 12th, a Saturday, the model understates the number of riders by a large margin. There was 0.2 mm of rain measured on this day, so the model is treating it as a rainy day, but perhaps it only rained a bit overnight and was clear the rest of the day.

Finally, on October 12th, a Thursday, the model again undercounts the number of trips, only expecting ~200 trips when in reality there over a thousand! There was 35 mm of rain measured that day, so even though the model expects the number of trips to keep decreasing linearly with rain, in practice if someone is going to bike in 20 mm of rain they're probably also going to bike in 30 mm of rain. Our model doesn't account for this.

There's some other potentially nonlinear effects that we're not including here. During the winter in Vancouver, the coldest days are often clear and sunny. I wonder if as we get into December and January, the temperature trend might reverse and we'll see more trips on the coldest days. If that's the case, we may need a more complex model to really describe how weather affects bike share users.

&lt;em&gt;All the source code used for data acquisition and analysis in this post is available on my &lt;a href="https://github.com/mjarrett/mobi"&gt;github page&lt;/a&gt;.&lt;/em&gt;

&lt;em&gt;To see more posts like this, follow me on twitter &lt;a href="https://twitter.com/MikeJarrett_"&gt;@MikeJarrett_&lt;/a&gt;.&lt;/em&gt;</description><category>bikes</category><category>bikeshare</category><category>datavis</category><category>mobi</category><category>python</category><category>Science</category><guid>https://notes.mikejarrett.ca/what-really-affects-bikeshare-use-in-vancouver/</guid><pubDate>Wed, 22 Nov 2017 07:32:26 GMT</pubDate></item><item><title>Mobi station activity</title><link>https://notes.mikejarrett.ca/mobi-station-activity/</link><dc:creator>Mike Jarrett</dc:creator><description>&lt;p&gt;I finally got around to learning how to map data on to maps with Cartopy, so here's some quick maps of Mobi bikeshare station activity.

First, an animation of station activity during a random summer day. The red-blue spectrum represents whether more bikes were taken or returned at a given station, and the brightness represents total station activity during each hour. I could take the time resolution lower than an hour, but I doubt the data is very meaningful at that level.

 

[video width="704" height="528" mp4="/images/movie_2017-08-18.mp4"][/video]

&lt;!--more--&gt;

 

There's actually less pattern to this than I expected. I thought that in the morning you'd see more bikes being taken from the west end and south False Creek and returned downtown, and vice versa in the afternoon. But I can't really make out that pattern visually.

I've also pulled out total station activity during the time I've been collecting this data, June through October 2017. I've separated it by total bikes taken and total bikes returned. A couple things to note about these images: many of these stations were not active for the whole time period, and some stations have been moved around. I've made no effort to account for this; this is simply the raw usage at each location, so the downtown

&lt;img class="alignnone size-full wp-image-210" style="font-size: 1rem;" src="https://notes.mikejarrett.ca/images/Total-Bikes-Taken-June-Oct-2017-1.png" alt="" width="640" height="480"&gt;&lt;img class="alignnone size-full wp-image-209" style="font-size: 1rem;" src="https://notes.mikejarrett.ca/images/Total-Bikes-Returned-June-Oct-2017-1.png" alt="" width="640" height="480"&gt;

The similarity in these maps is striking. Checking the raw data, I'm seeing incredibly similar numbers of bikes being taken and returned at each station. This either means that on aggregate people use Mobis for two way trips much more often than I expected; one way trips are cancelling each other out; or Mobi is rebalancing the stations to a degree that any unevenness is being masked out*. I hope to look more into whether I can spot artificial station balancing from my data soon, but we may have to wait for official data from Mobi to get around this.

&lt;em&gt;*There's also the possibility that my data is bad, but let's ignore that for now&lt;/em&gt;

Instead of just looking at activity, I tried to quantify whether there are different activity patterns at different stations. Like &lt;a href="http://mikejarrett.ca/blog/2017/10/machine-learning-with-vancouver-bike-share-data/"&gt;last week&lt;/a&gt;, I performed a primary component analysis (PCA) but with bike activity each hour in the columns, and each station as a row. I then plot the top two components which most explain the variance in the data.&lt;img class="alignnone size-full wp-image-213" src="https://notes.mikejarrett.ca/images/PCA_stations.png" alt="" width="640" height="480"&gt;

Like last week, much of the difference in station activity is explained by the total number of trips at each station, here represented on the X axis. There is a single main group of stations with a negative slope, but some outliers that are worth looking at. There are a few stations with higher Y values than expected.

&lt;img class="alignnone size-full wp-image-214" src="https://notes.mikejarrett.ca/images/PCA_stations_labeled1.png" alt="" width="640" height="480"&gt;

These 5 stations are all Stanley Park stations. There's another four stations that might be slight outliers.

&lt;img class="alignnone size-full wp-image-215" src="https://notes.mikejarrett.ca/images/PCA_stations_labeled2.png" alt="" width="640" height="480"&gt;

These are Anderson &amp;amp; 2nd (Granville Island); Aquatic Centre; Coal Harbour Community Centre; and  Davie &amp;amp; Beach. All seawall stations at major destinations. So all the outlier stations are stations that we wouldn't expect to show regular commuter patterns, but more tourist-style activity.

I was hoping to see different clusters to represent residential area stations vs employment area stations, but these don't show up. Not terribly surprising since the Mobi stations cover an area of the city where there is fairly dense residential development almost everywhere. This fits with our maps of station activity, where we saw that there were no major difference between bikes taken and bikes returned at each station.

&lt;em&gt;All the source code used for data acquisition and analysis in this post is available on my &lt;a href="https://github.com/mjarrett/mobi"&gt;github page&lt;/a&gt;.&lt;/em&gt;

&lt;em&gt;To see more posts like this, follow me on twitter &lt;a href="https://twitter.com/mikejarrett_"&gt;@mikejarrett_&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</description><category>bikes</category><category>datavis</category><category>mobi</category><category>python</category><category>Science</category><category>vancouver</category><guid>https://notes.mikejarrett.ca/mobi-station-activity/</guid><pubDate>Sun, 05 Nov 2017 05:36:22 GMT</pubDate></item><item><title>Machine learning with Vancouver bike share data</title><link>https://notes.mikejarrett.ca/machine-learning-with-vancouver-bike-share-data/</link><dc:creator>Mike Jarrett</dc:creator><description>&lt;p&gt;Six months ago I came across Jake VanderPlas' blog post &lt;a href="https://jakevdp.github.io/blog/2015/07/23/learning-seattles-work-habits-from-bicycle-counts/"&gt;examining Seattle bike commuting habits through bike trip data&lt;/a&gt;. I wanted to try to recreate it for Vancouver, but the city doesn't publish detailed bike trip data, just monthly numbers. For plan B, I looked into Mobi bike share data. But still no published data! Luckily, Mobi does publish an API with the number of bike at each station. It doesn't give trip information, but it's a start.

&lt;!--more--&gt;

&lt;em&gt;All the code needed to recreate this post is available on &lt;a href="https://github.com/mjarrett/mobi"&gt;my github page&lt;/a&gt;.&lt;/em&gt;
&lt;/p&gt;&lt;h3&gt;Data Acquisition&lt;/h3&gt;
The first problem was to read the API and take a guess at station activity. To do this, I query the API every minute. Whenever the bike count at a station changes, this is counted as bikes being taken out or returned. I don't know exactly how often Mobi updates this API, but I'm certainly undercounting activity -- whenever two people return a bike and take a bike within a minute or so of each other I'll miss the activity. But it's good enough for my purposes, and I'm more interested in trends than total numbers anyway.

I had two main problems querying the API: First, I'd starting by running the query script on my home machine. This meant that any computer downtime meant missing data. There's a few days missing while I updated my computer. Eventually I migrated to a google cloud server, so downtime is no longer an issue, but this introduced the second problem: time zones. I hadn't set a time zone for my new server, so all the times were recorded as UTC, while earlier data had been recorded in local Vancouver time. It took a long time of staring at the data wondering why it didn't make sense for me to realize what had happened, but luckily an easy fix in Pandas.
&lt;h3&gt;Analysis&lt;/h3&gt;
&lt;img class="aligncenter wp-image-168 size-full" src="https://notes.mikejarrett.ca/images/hourly_usage_may-sep.png" alt="" width="640" height="480"&gt;

Our long stretch of good weather this summer is visible in the data. Usage was pretty consistent over July and August, and began to fall off near the end of September when the weather turned. I'll be looking more into the relationship between weather and bike usage once I have more off-season data, but for now I'm more interested in zooming in and looking at daily usage patterns. Looking at a typical week in mid summer, we see weekdays showing a typical commuter pattern with morning and evening peaks and a midday lull. One thing that jumps out is the afternoon peak being consistently larger than the morning peak. With bike share, people have the option to take the bus to work in the morning and then pick up a bike afterwork if they're in the mood. Weekends lose that bimodal distribution and show a single normal distribution centered in the afternoon. On most weekend days and some weekdays, there is a shoulder or very minor peak visible in the late evening, presumably people heading home from a night out.

 

&lt;img class="aligncenter wp-image-166 size-full" src="https://notes.mikejarrett.ca/images/weekdata-2017-07-31-2017-08-06.png" alt="" width="640" height="480"&gt;

Looking at the next week, Monday immediately jumps out as showing a weekend pattern instead of a weekday. That Monday, of course, is the Monday of the August long weekend.

&lt;img class="aligncenter wp-image-167 size-full" src="https://notes.mikejarrett.ca/images/weekdata-2017-08-07-2017-08-13.png" alt="" width="640" height="480"&gt;

So, by eye we can fairly easily distinguish weekday and weekend travel patterns. How can we train a computer to do the same?

First, I pivoted my data such that each row is a day, and each column is the hourly bike activity at each station (# columns = # stations * 24). I decided to keep the station information instead of summing across stations, but both give about the same result. This was provided as input to the &lt;a href="http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html"&gt;primary component analysis (PCA) class of the Scikit-Learn Python package&lt;/a&gt;. PCA attempts to reduce the dimensionality of a data set (in our case, columns) while preserving the variance. For visualization, we can plot our data based on the the two components which most explain the variance in the data. Each point is a single day, colour labelled by total number of trips that day.

&lt;img class="wp-image-192 size-full" style="font-size: 1rem;" src="https://notes.mikejarrett.ca/images/PCA_numtrips-2.png" alt="" width="640" height="480"&gt; PCA coloured by number of daily trips

It's apparent that the first component (along the X axis) corresponds roughly (but not exactly) to total number of trips. But what does the Y axis represent? To investigate further, we label the data points by day of week.

&lt;img class="wp-image-191 size-full" style="font-size: 1rem;" src="https://notes.mikejarrett.ca/images/PCA_dayofweek-2.png" alt="" width="640" height="480"&gt; PCA coloured by day of week

The pattern is immediately clear. Weekdays are clustered at the bottom of our plot, and weekends are clustered at the top. A few outliers jump out. There are 3 Mondays clustered in with the weekend group. These turn out to be the Canada Day, BC Day and Labour Day stat holidays.

&lt;img class="wp-image-190 size-full" style="font-size: 1rem;" src="https://notes.mikejarrett.ca/images/PCA_dayofweek_mondays-2.png" alt="" width="640" height="480"&gt; PCA with noteable Mondays labelled

 

 

Finally, I wanted to try unsupervised clustering to see if weekday and weekend clusters are separated enough to be distinguished automatically. For this, I used the &lt;a href="http://scikit-learn.org/stable/modules/mixture.html"&gt;GaussianMixture class from Scikit-learn&lt;/a&gt;. Here, we try to automatically split our data into a given number of groups, in this case two.

&lt;img class="wp-image-193 size-full" src="https://notes.mikejarrett.ca/images/PCA_clustering-2.png" alt="" width="640" height="480"&gt; PCA and unsupervised clustering of June-September bike share usage

Not quite. There is a group of low-volume weekend days in the top right cornerthat can't be automatically distinguished from weekdays. All these days are in June and September. Maybe with more non-summer data this will resolve itself.

Out of curiosity, I re-ran the PCA and unsupervised clustering with only peak season data (July and August). Here, with more a more homogenous dataset, clustering works much better. In fact, only the first component (plotted along the X axis) is needed to distinguish between usage patterns.

&lt;img class="wp-image-194 size-full" src="https://notes.mikejarrett.ca/images/PCA_clustering-3.png" alt="" width="640" height="480"&gt; PCA and unsupervised clustering of July and August bike share usage

Bike share usage will obviously decline during Vancouver's wet season, but I'm very interested to see how usage patterns will differ during the lower volume months.

 

&lt;em&gt;All the source code used for data acquisition and analysis in this post is available on my &lt;a href="https://github.com/mjarrett/mobi"&gt;github page&lt;/a&gt;.&lt;/em&gt;

&lt;em&gt;To see more posts like this, follow me on twitter &lt;a href="https://twitter.com/MikeJarrett_"&gt;@MikeJarrett_&lt;/a&gt;.&lt;/em&gt;</description><category>bikes</category><category>datavis</category><category>mobi</category><category>python</category><category>Science</category><guid>https://notes.mikejarrett.ca/machine-learning-with-vancouver-bike-share-data/</guid><pubDate>Mon, 23 Oct 2017 12:00:19 GMT</pubDate></item></channel></rss>