Low-pass, high-pass and band-pass filtering
Today let's understand filtering: how to choose which frequencies of a series survive, and which ones get erased.
Northside Diner is a lunch restaurant that logged how many lunch covers it served every day for ten weeks, seventy days in all, averaging 119.2 a day with a standard deviation of 25.4. Two real cycles sit hidden inside that series: one repeating every 7 days, at frequency 1/7, and a smaller one repeating every 3.5 days, at frequency 2/7. Neither cycle is visible by eye in the raw line below.
Toggle between line and point to look at that raw shape one more time. Everything from here changes what this line looks like: keeping its slow rise and fall, keeping only its jitter, or keeping just a narrow slice in between.
A filter is a weighted average of nearby values
Rebuild Northside Diner's series first, so every step in this lesson works from the same real numbers.
A filter turns a series into a new series where every output value is a weighted sum of nearby input values. The simplest filter is a moving average: replace each day's value with the average of that day and some of its neighbours. In base R, filter() builds one directly. Its second argument is the vector of weights, and its third argument, sides, decides where the window sits relative to each day. sides = 2 centers the window: each output uses one day before, the day itself, and one day after. sides = 1 trails it: each output uses only the day itself and days before it, never a day that has not happened yet.
Build a 3-day centered moving average, giving equal weight to a day and each of its two neighbours.
rep(1/3, 3) hands filter() three equal weights, each 1/3, so every output is a plain average of three days, not a scaled-up or scaled-down sum. Day 1 comes back NA, since a centered 3-day window needs a day before day 1, and there isn't one. Day 5 comes back 152.33, the average of days 4, 5 and 6: (134 + 174 + 149) / 3.