Modify Whole Table or Plot - Replace with Rolling Averages
Jump to navigation
Jump to search
Q Technical Reference
Q Technical Reference
Q Technical Reference > Creating And Modifying Tables
Q Technical Reference > Setting Up Data > Creating New Variables
Q Technical Reference > Updating and Automation > Automation Online Library
Q Technical Reference > Updating and Automation > JavaScript > Table JavaScript and Plot JavaScript
Rule Online Library
This rule computes a rolling average on a table. There are options for controlling the number of periods in the moving average and whether to roll by the rows or columns.
Technical details
- A lagged rolling average is computed. For example, if January has a score of 3, February 4 and March 6, the 3-period rolling average for March is (3 + 4 + 6) / 3 = 4.33333333. More sophisticated rolling averages can be computed using Time Series Analysis (see How to Compute a Moving Average).
- Where values cannot be computed due to insufficient data, the value is shown as NaN. For example, if January has a score of 3, February 4 and March 6, the 3-period rolling average for the three months, respectively, are NaN, NaN and 4.33333333.
- This rule is only applied to the first Statistic selected in each of Statistics - Cells and whichever is appropriate of Statistics - Below and Statistics - Right.
- You may not have a NET in the variable containing the dates.
- The statistical testing results on the table are not changed by this rule. That is, they reflect the results for the original, un-rolled statistics.
How to apply this rule
For the first time in a project
- Select the table(s)/chart(s) that you wish to apply the rule to.
- Start typing the name of the Rule into the Search features and data box in the top right of the Q window.
- Click on the Rule when it appears in the QScripts and Rules section of the search results.
OR
- Select Automate > Browse Online Library.
- Choose this rule from the list.
Additional applications of the rule
- Select a table or chart that has the rule and any table(s)/chart(s) that you wish to apply the rule to.
- Click on the Rules tab (bottom-left of the table/chart).
- Select the rule that you wish to apply.
- Click on the Apply drop-down and choose your desired option.
- Check New items to have it automatically applied to new items that you create. Use Edit > Project Options > Save as Template to create a new project template that automatically uses this rule.
Removing the rule
- Select the table(s)/chart(s) that you wish to remove the rule from.
- Press the Rules tab (bottom-right corner).
- Press Apply next to the rule you wish to remove and choose the appropriate option.
How to modify the rule
- Click on the Rules tab (bottom-left of the table/chart).
- Select the rule that you wish to modify.
- Click Edit Rule and make the desired changes. Alternatively, you can use the JavaScript below to make your own rule (see Customizing Rules).
JavaScript
rollingAverage = function(x, n_periods) {
Array.prototype.sum = function () {
let total = 0;
let i = this.length;
while (i--) {
total += this[i];
}
return total;
}
let n_columns = x[0].length;
let n_rows = x.length;
let result = new Array(n_rows);
for (let c = 0; c < n_columns; c++) {
let sum = 0;
for (let r = 0; r < n_rows; r++) {
if (c == 0)
result[r] = new Array(n_columns);
if (r >= n_periods - 1) {
let array_subset = x.map(function (arr) { return arr[c]; } ).slice(r - n_periods + 1, r + 1);
result[r][c] = array_subset.sum() / n_periods;
} else {
result[r][c] = NaN;
}
}
}
return(result);
}
includeWeb("Table JavaScript Utility Functions");
// For R tables where columns are not recognised, this rule only works when there is 1 statistic (column)
if (table.statistics.length > 1) {
excludeRTablesWithoutColumns();
}
// Create the form
form.setHeading('Rolling (Moving) Average');
let description = form.newLabel("Replace the values of the first statistic with rolling averages.");
description.lineBreakAfter = true;
let number_label = form.newLabel('Number of periods to roll:');
let numeric_up_down = form.newNumericUpDown('periods');
numeric_up_down.lineBreakAfter = true;
numeric_up_down.setDefault(3);
numeric_up_down.setIncrement(1);
numeric_up_down.setMinimum(1);
let within_rows_cb = form.newCheckBox('check',"Dates are in the rows");
within_rows_cb.setDefault(false);
form.setInputControls([description, number_label, numeric_up_down, within_rows_cb]);
let within_rows = within_rows_cb.getValue()
let n_periods = numeric_up_down.getValue()
form.setSummary(n_periods + " period rolling average (within " + (within_rows ? "columns" : "rows") + ")");
let labs = within_rows ? table.rowLabels : table.columnLabels;
if (labs == null) {
form.ruleNotApplicable("there are no " + (within_rows ? "rows" : "columns") + " to average over. Toggle the 'Dates are in the rows' setting above");
}
if (labs.indexOf("Total") != -1 || labs.indexOf("NET") != -1)
form.ruleNotApplicable("this rule can only be applied when the date labels don't contain a NET or Total");
if (!within_rows && n_periods > table.numberColumns)
form.ruleNotApplicable("there are fewer columns than periods to average over");
if (within_rows && n_periods > table.numberRows)
form.ruleNotApplicable("there are fewer rows than periods to average over");
if (table.statistics[0] == "Text")
form.ruleNotApplicable("this rule can only be applied to a numeric table. Try using Text Analysis - Automatic Categorization to create categorical variables to tabulate");
// Peforming rolling average on main table.
let values = table.get(table.statistics[0]);
if (typeof values[0][0] != "number")
form.ruleNotApplicable("the first statistic in the table is not numeric");
if (!within_rows)
values = Q.transpose(values);
values = rollingAverage(values, n_periods);
if (!within_rows)
values = Q.transpose(values);
table.set(table.statistics[0], values);
// Peforming rolling average on marginal table table.
if (within_rows ? (rightTableExists() && right_table.statistics.length > 0) : (belowTableExists() && below_table.statistics.length > 0)) {
let marginal_values = within_rows ? right_table.get(right_table.statistics[0]) : below_table.get(below_table.statistics[0]);
if (typeof marginal_values[0][0] == "number") { // Do not try to average over column comparisons strings
let needs_transpose = marginal_values.length == 1;
if (needs_transpose) {
marginal_values = Q.transpose(rollingAverage(Q.transpose(marginal_values), n_periods));
} else {
marginal_values = rollingAverage(marginal_values, n_periods);
}
if (within_rows)
right_table.set(right_table.statistics[0], marginal_values);
else
below_table.set(below_table.statistics[0], marginal_values);
}
}
See also
- User Input for Rules for technical information on Rules.
- Rule Online Library for other examples of Rules.
- Table JavaScript and Plot JavaScript for the JavaScript that is used to write custom rules.
- JavaScript for information about the JavaScript programming language.
Q Technical Reference
Q Technical Reference
Q Technical Reference > Creating And Modifying Tables
Q Technical Reference > Setting Up Data > Creating New Variables
Q Technical Reference > Updating and Automation > Automation Online Library
Q Technical Reference > Updating and Automation > JavaScript > Table JavaScript and Plot JavaScript
Rule Online Library