Beispiel #1
0
 def _prophet_seasonality(request, context):
     """
     Provide the seasonality component of the Prophet timeseries forecast. Scalar function.
     :param request: an iterable sequence of RowData
     :param context: not used for now
     :return: the forecasted value for each row
     :
     :Qlik expression example:
     :<AAI Connection Name>.Prophet_Seasonality(Month, $(vConcatSeries), $(vHolidays), 'seasonality=yearly, freq=MS, debug=true')
     :The fourth argument in the Qlik expression is a string of parameters. 
     :This should take the form of a comma separated string:
     :e.g 'seasonality=yearly, freq=MS, debug=true' or 'seasonality=weekly, freq=D'
     :
     :Parameters accepted for the Prophet() function are: cap, floor, changepoint_prior_scale, interval_width, 
     :lower_window, upper_window 
     :
     :Parameters accepted for the make_future_dataframe() function are: freq
     :
     :For more information on these parameters go here: https://facebook.github.io/prophet/docs/quick_start.html
     :
     :Additional parameters used are: return, take_log, debug
     :
     :cap = 1000 : A logistic growth model can be defined using cap and floor. Values should be double or integer
     :changepoint_prior_scale = 0.05 : Decrease if the trend changes are being overfit, increase for underfit
     :interval_width = 0.08 : Set the width of the uncertainty intervals
     :lower_window = -1 : Only used with holidays. Extend the holiday by certain no. of days prior to the date.
     :upper_window = 1 : Only used with holidays. Extend the holiday by certain no. of days after the date.
     :freq = MS : The frequency of the time series. e.g. MS for Month Start. See the possible options here:
     :          : http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases
     :return = yhat : Any of the options in the forecast result. You can see these options with debug=true 
     :              : yhat, yhat_upper, yhat_lower : Forecast, upper and lower limits
     :              : y_then_yhat, y_then_yhat_upper, y_then_yhat_lower : Return forecast only for forecast periods
     :              : trend, trend_upper, trend_lower : Trend component of the timeseries
     :              : seasonal, seasonal_upper, seasonal_lower: Seasonal component of the timeseries 
     :take_log = false : Apply logarithm to the values before the forecast. Default is true
     :debug = true : Print exexution information to the terminal and logs in ..\logs\Prophet Log <n>.txt
     """
     
     # Get a list from the generator object so that it can be iterated over multiple times
     request_list = [request_rows for request_rows in request]
                           
     # Create an instance of the ProphetForQlik class
     # This will take the request data from Qlik and prepare it for forecasting
     predictor = ProphetForQlik.init_seasonality(request_list)
     
     # Calculate the forecast and store in a Pandas series
     forecast = predictor.predict()
     
     # Values in the series are converted to type SSE.Dual
     response_rows = forecast.apply(lambda result: iter([SSE.Dual(numData=result)]))
     
     # Values in the series are converted to type SSE.Row
     # The series is then converted to a list
     response_rows = response_rows.apply(lambda duals: SSE.Row(duals=duals)).tolist()        
     
     # Iterate over bundled rows
     for request_rows in request_list:
         # Yield Row data as Bundled rows
         yield SSE.BundledRows(rows=response_rows)  
Beispiel #2
0
    def _prophet(request, context):
        """
        Provide a timeseries forecast using Facebook's Prophet library. Scalar function.
        :param request: an iterable sequence of RowData
        :param context: not used for now
        :return: the forecasted value for each row
        :
        :Qlik expression example:
        :<AAI Connection Name>.Prophet(MonthStartDate, sum(Value), 'return=yhat, freq=MS, debug=true')
        :The third argument in the Qlik expression is a string of parameters. 
        :This should take the form of a comma separated string:
        :e.g 'return=yhat, freq=MS, debug=true' or 'return=yhat_upper, freq=MS'
        :
        :<AAI Connection Name>.Prophet_Holidays(ForecastDate, sum(Value), Holiday, 'return=yhat, freq=D, debug=true')
        :In the holidays variant the third argument is a field containing the holiday name or NULL for each row.
        :
        :Parameters accepted for the Prophet() function are: cap, floor, changepoint_prior_scale, interval_width, 
        :lower_window, upper_window 
        :
        :Parameters accepted for the make_future_dataframe() function are: freq
        :
        :For more information on these parameters go here: https://facebook.github.io/prophet/docs/quick_start.html
        :
        :Additional parameters used are: return, take_log, debug, load_script
        :
        :cap = 1000 : A logistic growth model can be defined using cap and floor. Values should be double or integer
        :changepoint_prior_scale = 0.05 : Decrease if the trend changes are being overfit, increase for underfit
        :interval_width = 0.08 : Set the width of the uncertainty intervals
        :lower_window = 1 : Only used with holidays. Extend the holiday by certain no. of days prior to the date.
        :upper_window = 1 : Only used with holidays. Extend the holiday by certain no. of days after the date.
        :freq = MS : The frequency of the time series. e.g. MS for Month Start. See the possible options here:
        :          : http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases
        :return = yhat : Any of the options in the forecast result. You can see these options with debug=true
        :              : yhat, yhat_upper, yhat_lower : Forecast, upper and lower limits
        :              : y_then_yhat, y_then_yhat_upper, y_then_yhat_lower : Return forecast only for forecast periods
        :              : trend, trend_upper, trend_lower : Trend component of the timeseries
        :              : seasonal, seasonal_upper, seasonal_lower: Seasonal component of the timeseries 
        :take_log = false : Apply logarithm to the values before the forecast. Default is true
        :debug = true : Print execution information to the terminal and logs in ..\logs\Prophet Log <n>.txt
        """

        # Get a list from the generator object so that it can be iterated over multiple times
        request_list = [request_rows for request_rows in request]

        # Calculate timings for the components of the forecasting
        # The results will be stored in ..\logs\Prophet Performance Log.txt
        # The request_list line above is not timed as the generator can only be iterated once
        # ProphetForQlik.timeit(request_list)

        # Create an instance of the ProphetForQlik class
        # This will take the request data from Qlik and prepare it for forecasting
        predictor = ProphetForQlik(request_list, context)

        # Calculate the forecast and store in a Pandas series
        forecast = predictor.predict()

        # Check if the response is a DataFrame.
        # This occurs when the load_script=true argument is passed in the Qlik expression.
        response_is_df = isinstance(forecast, pd.DataFrame)

        # Convert the response to a list of rows
        forecast = forecast.values.tolist()

        # We convert values to type SSE.Dual, and group columns into a iterable
        if response_is_df:
            response_rows = [
                iter([SSE.Dual(strData=row[0]),
                      SSE.Dual(numData=row[1])]) for row in forecast
            ]
        else:
            response_rows = [iter([SSE.Dual(numData=row)]) for row in forecast]

        # Values are then structured as SSE.Rows
        response_rows = [SSE.Row(duals=duals) for duals in response_rows]

        # Get the number of rows in the request
        num_request_bundles = len(request_list)

        # Get the number of rows in the response
        num_rows = len(response_rows)

        # Calculate the number of rows to send per bundle
        if num_rows >= num_request_bundles:
            rows_per_bundle = len(response_rows) // len(request_list)
        else:
            rows_per_bundle = num_rows

        # Stream response as BundledRows
        for i in range(0, len(response_rows), rows_per_bundle):
            # Yield Row data as Bundled rows
            yield SSE.BundledRows(rows=response_rows[i:i + rows_per_bundle])