2

df

Date        Col1   Col2   Col3
2016-11-1    12     13     14
2016-10-1    2      3      1
2016-03-01   2      1      1 
and so on

Code to decompose time series to get seasonality, trends, observed and residual values:

from statsmodels.tsa.seasonal import seasonal_decompose
from matplotlib import dates as mdates
years = mdates.YearLocator()    # only print label for the years
months = mdates.MonthLocator()  # mark months as ticks
years_fmt = mdates.DateFormatter('%Y')
fmt = mdates.DateFormatter('%b')

df = df.set_index('Date')


s_dec_multiplicative = seasonal_decompose(df['Col1'], model = "multiplicative")
s_dec_multiplicative.plot()

s_dec_multiplicative.xaxis.set_major_locator(years)
s_dec_multiplicative.xaxis.set_minor_locator(months)
s_dec_multiplicative.xaxis.set_major_formatter(years_fmt)
s_dec_multiplicative.xaxis.set_minor_formatter(fmt)
plt.show()

Problem: I want tickers for JAN,FEB, MAR etc like that for all months. Years should be mentioned like 2016, 2017 and so on and months should be in between with small ticks.

ERROR:

---> 12 s_dec_multiplicative.xaxis.set_major_locator(years)
AttributeError: 'DecomposeResult' object has no attribute 'xaxis'
Sergey Bushmanov
  • 23,310
  • 7
  • 53
  • 72
noob
  • 3,601
  • 6
  • 27
  • 73

1 Answers1

3

Your problem is that you're trying to change attribute of DecomposeResult object whereas you're supposed to work on ax object.

Let's retrieve some toy time series data:

from pandas_datareader import data
goog = data.DataReader("GOOG", "yahoo")["Adj Close"]
goog.plot();

enter image description here

Now let's do the desired decomposition and put the results into Pandas' df:

from statsmodels.tsa.seasonal import seasonal_decompose
s_dec_multiplicative = seasonal_decompose(goog, model = "multiplicative", freq=12)

observed = s_dec_multiplicative.observed
seasonal = s_dec_multiplicative.seasonal
residual = s_dec_multiplicative.resid

df = pd.DataFrame({"observed":observed, "seasonal":seasonal,"residual":residual}

Finally, we're ready to plot:

from matplotlib import dates as mdates
years = mdates.YearLocator()    # only print label for the years
months = mdates.MonthLocator()  # mark months as ticks
years_fmt = mdates.DateFormatter('%Y-%b')
fmt = mdates.DateFormatter('%b')

_, axes = plt.subplots(nrows=3,ncols=1, figsize=(20, 10))
for i, ax in enumerate(axes):
    ax = df.iloc[:,i].plot(ax=ax)
    ax.xaxis.set_major_locator(years)
    ax.xaxis.set_major_formatter(years_fmt)
    ax.xaxis.set_minor_locator(months)
    ax.xaxis.set_minor_formatter(fmt)
    ax.set_ylabel(df.iloc[:,i].name)
    plt.setp(ax.xaxis.get_minorticklabels(), rotation=90)
    plt.setp(ax.xaxis.get_majorticklabels(), rotation=90)

enter image description here

Sergey Bushmanov
  • 23,310
  • 7
  • 53
  • 72
  • i have upvoted but cannot accept as answer as the answer is not working on dataframe, may be your data is series data. Can you try for random data in dataframes where we are trying to plot seasonality for a column. Also trend is the 4th graph apart from seasoanlity, observed and residual – noob Feb 04 '20 at 13:00
  • Do you mean the code I presented is not working at your side? As far as trend is concerned you may add it by `trend = s_dec_multiplicative.trend`. – Sergey Bushmanov Feb 04 '20 at 13:03
  • one thing the difference between your goog and my dataframe is that in my dataframe there is only one value for each month and year, for eg. May 2016 will hv just one value, similarly jun 2016 will hv just one value and so on. whereas your goog has multiple values for one month – noob Feb 05 '20 at 08:54
  • @ShailajaGuptaKapoor Thanks for upvoting and accepting. Next time you ask for assistance think about [mcve], including a representative sample of your data. That will increase significantly the chances you get a quality response. – Sergey Bushmanov Feb 06 '20 at 16:43