Working with Time-Indexed Data in pandas
The case study predicts how many people rent a bike at one Citi Bike station for a given time, using station data loaded for August 2015.
A Practical Question About Bikes at One Station
Andreas wants to know whether any bikes will be left at the rental station in front of his house. That is a practical question, and this case study answers it by working with real rental data rather than a formula. In New York, Citi Bike runs a network of bicycle rental stations spread across the city, operating on a subscription system. Because the bike rental data is made public in an anonymized form, it can be analyzed in many different ways.
The prediction task is precise: for a given time and day, estimate how many people will rent a bike at that station. Everyday knowledge helps here. Anyone who has watched a busy street knows that rentals rise and fall with the time of day. The rest of this article follows the code that prepares the data for that prediction, and it asks you to check the output of each step as you go, so that you can tell where a result would go wrong if it did.
Loading One Station's Rentals
The first step loads the August 2015 data for one particular station as a pandas DataFrame. A helper function from the mglearn library returns that data, and the result is assigned to a variable named citibike. At this point nothing about the prediction happens yet. The line only brings the data into memory, so it is worth reading it as a loading step and nothing more.
Once the data is loaded, the cheapest way to check it is to look at the first rows. The head() method shows those rows together with their time labels, so you can confirm that the data is the station you intended before going further. The diagram below shows the shape of the printed table for the first five intervals.
The printed table has two parts that matter. The index is labeled starttime, and each row carries one value. Each row covers one three-hour interval, and the value is the figure the data holds for that interval. The values are shown with a decimal point, such as 3.0 and 41.0. That tells you the column is stored as floating-point numbers, even though the quantities being counted are rentals.
Reading the Pairing of Labels and Values
Each time label is the start of its interval, and each value belongs to the label it is paired with. The pairing is the single most important thing to read correctly in the printed table. If you attach a value to the wrong label, you will reason about the wrong part of the day. For example, attaching 41.0 to the 06:00 label would make you think the station was busy at 06:00, when that value belongs to a different interval.
What do you think happens?
Which value belongs to the 06:00 label in the printed first five rows?
Reveal answer
9.0
The rows run in order from midnight in three-hour steps, so the 00:00 row is first, the 03:00 row is second, and the 06:00 row is third. The third row carries 9.0. The value 41.0 is the fourth row, which belongs to the 09:00 interval, not to 06:00.
What Resampling Does to the Rows
The source states that the data is resampled into three-hour intervals to obtain the main trends. Resampling means regrouping observations that are tied to time into new, regular time buckets, and then working with one value per bucket. Here the bucket width is three hours, which is the meaning of the Freq: 3H label in the printed output. A bucket that begins at midnight, then 03:00, then 06:00, and so on, gives one row per interval across each day.
The effect on the rows is a change in granularity. Many individual rental observations that fall inside one three-hour window are replaced by a single row for that window. The row's value is the count the data holds for that interval. The diagram below shows two adjacent buckets, with several raw rental observations feeding each bucket and one value coming out.
Why Three Hours Reveals the Trend
The reason for this choice is the trend, not the detail. A single bucket that covers three hours smooths out minute-to-minute noise and leaves the daily pattern visible. The source describes the goal as obtaining the main trends for each day. In other words, the resampled table answers how activity moves across a day, which is the kind of question Andreas needs answered.
Reading the First Three Buckets as a Daily Pattern
Using the first three resampled rows of the station data, which print 3.0, 0.0 and 9.0 under the 00:00, 03:00 and 06:00 labels, describe what the rows show about activity from midnight to 06:00.
- 1Identify the row order
The buckets begin at midnight and advance in three-hour steps, so the rows are read in order: 00:00, then 03:00, then 06:00.
- 2Pair each label with its value
The 00:00 label carries 3.0, the 03:00 label carries 0.0, and the 06:00 label carries 9.0. Each value stays attached to the label that starts its interval.
- 3Read the change across buckets
The count drops from 3.0 to 0.0 between midnight and 03:00, then rises to 9.0 by 06:00. Each step compares one three-hour window with the next.
The rows show a quiet window between 03:00 and 06:00 at the start of the day, followed by a rise by 06:00. This is a trend across the day rather than a single minute of activity.
Tracing the Data Through Each Stage
After loading and resampling, the next move is visual. The source shows a plot of the rental frequencies for the whole month, with the number of bike rentals drawn over time for the selected station. Each point on the plot corresponds to one of the resampled three-hour rows, so the plot is a picture of the same table you printed earlier, extended across August 2015. Peaks and quiet stretches become visible as a pattern across days, which a list of printed numbers hides.
The order of these stages is part of the lesson. Each stage consumes the output of the stage before it. The loaded DataFrame feeds the resampling step, and the resampled table feeds the plot. The diagram below traces that chain from left to right so you can see what each stage hands to the next.
Finding Where a Prediction Diverges
When a result diverges from what you expected, the efficient move is to narrow the search instead of rereading all the code at once. Work through the stages in order, using the printed table as the cheapest checkpoint.
- 1Start with the printed table from
head(), because it is the cheapest checkpoint. - 2If the first rows already disagree with expectation, the fault lies in loading or in the pairing of labels and values.
- 3If the first rows are correct but the plot disagrees, the fault lies in a later stage, such as the resampling or the plotting step.
Common mistake Reading a value under the wrong time label
What it looks likeAttaching 41.0 to the 06:00 label and concluding the station was busy at 06:00.
Why it failsEach value belongs to the label that starts its own interval. Under the printed order, 41.0 is the fourth row, not the third.
Do this insteadRead each row as a pair. Confirm the label first, then the value on the same row.
Common mistake Assuming the decimal point means fractional rentals
What it looks likeBelieving 3.0 means three and a half rentals.
Why it failsThe decimal point shows that the column is stored as floating-point numbers. The quantities still count rentals.
Do this insteadRead the value as a whole count of rentals for that three-hour interval.
Common mistake Rereading the whole program when the plot looks wrong
What it looks likeReviewing every line of code without first checking the printed first rows.
Why it failsThe fault could sit in loading, resampling, or plotting. Checking everything at once hides which stage actually caused the problem.
Do this insteadCheck head() first, then the resampled table, then the plot, in that order.
Common mistake Forgetting that the plot is drawn from the resampled table, so a plot that disagrees may come from a different table than the one you printed
Practice Locating a Fault
Your head() output shows the expected station's time labels, but 41.0 is printed beside the 06:00 label, and your plot looks correct for the rest of August. Which stage do you check first, and what does that tell you about where the fault is?
Hints
- The plot is drawn from the resampled table, so if the plot is correct, the later stages are likely fine.
- Recall that
head()is the cheapest checkpoint and that the pairing of labels and values is established in the printed table. - Ask whether the mismatch is between a label and its value, which would point to the loading or pairing stage.
Key Takeaways
- Loading the data gives a pandas
DataFrame, andhead()lets you check the first rows and their time labels before going further. - Resampling into three-hour intervals turns the data into one row per bucket, with one value per interval, which reveals the main trends for each day.
- Each value belongs to the time label that starts its interval, so misreading that pairing is an early place for a wrong prediction to start.
- When a result diverges, check each stage in order: loading, then resampling, then plotting, narrowing the search with the printed
head()table first.