Modify Tables or Plots - Show Average Rank

From Q
Jump to navigation Jump to search

This rule adds an additional Statistic to a SUMMARY of a Number - Multi question, showing the Average Rank.

Example

AverageRank.png

Technical details

  1. This Rule requires Q 4.11 or later.
  2. By default, the highest value is given the highest rank. For example, if there are 6 items, the value with the highest value is given a rank of 6, even if all the other values are missing. If Reverse ranking (highest score is given a rank of 1) is checked, the highest value is instead given a value of 1.
  3. Where Treatment of ties is set to Average rank, tied values are assigned the average rank. For example, if there are 6 items, and three of them share the highest value, they will be given a rank of 5 (i.e., (4 + 5 + 6) / 3). Where set to Highest rank, the highest possible value is set. For example, if there are 6 items, and three share the highest value, they are all assigned a value of 6, unless Reverse ranking (highest score is given a rank of 1) is checked, in which case they are assigned a value of 1.
  4. Where Treatment of ties is set to Average rank and Reverse ranking (highest score is given a rank of 1) is checked, this corresponds to the Excel function RANK.AVG.
  5. Where Treatment of ties is set to Highest rank and Reverse ranking (highest score is given a rank of 1) is checked, this corresponds to the deprecated Excel function RANK.
  6. NETs are given ranks of NaN.

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

includeWeb("QScript Utility Functions");
includeWeb('Table JavaScript Utility Functions'); 

excludeRTables();

// Checking if the rule is applicable
let blue = table.blueQuestion;
if (blue.questionType != "Number - Multi" || table.brownQuestion != "SUMMARY")
  form.ruleNotApplicable(correctTerminology("this rule requires a table that is a SUMMARY of a Number - Multi question"));
 
let statistic_to_replace = "Not Duplicate";
 
// Creating form.
form.setHeading("Show Average Rank");
form.setSummary("Show average rank");
let description = form.newLabel(correctTerminology("Shows the average rank of each item based on the raw data."));
description.lineBreakAfter = true;
if (fileFormatVersion() < 8.81) {
    form.ruleNotApplicable("this rule requires Q 4.11 or higher. Please contact Q Support")
} else { 
    var reverse_checkbox = form.newCheckBox("Highest1", "Reverse ranking (highest score is given a rank of 1)");
    reverse_checkbox.lineBreakAfter = true;
    reverse_checkbox.setDefault(false);
     
    var tie_treatment =  ["Average rank", "Highest rank"];
    var ties_combo = form.newComboBox('ties', tie_treatment);
    ties_combo.setDefault(tie_treatment[0]);
    var tie_label = form.newLabel("Treatment of ties");
    form.setInputControls([description, reverse_checkbox, tie_label, ties_combo]);
     
    // Extracting values from form.
    var reverse = reverse_checkbox.getValue();
    var average_rank = ties_combo.getValue() == tie_treatment[0];
     
    // Function for sorting and cleaning the data.
    var not_duplicates_raw = table.get("Not Duplicate");
    var n_variables = not_duplicates_raw.length;                                   
    var not_duplicate = new Array(n_variables);
    var n_non_NET = 0;
     
    for (var i = 0; i < n_variables; i++) { 
        not_duplicate[i] = not_duplicates_raw[i][0] == 1;
        if (not_duplicate[i])
            n_non_NET++;
    }
    sortValues = function(x) {
        var result = [];
        for(var i = 0; i < n_variables; i++) {
            var v = x[i];
            if (not_duplicate[i]  && !isNaN(v))
                result.push(v);
        }
        return(result.sort(function(a, b){return b - a}));
    }
     
    // Computing average ranks.
    var wgt = table.weight;
    if (wgt != null)
        wgt = wgt.rawValues;
    var raw_table = calculateTable(table.blue, "RAW DATA", ['!UseQFilters'], null);
    var raw_data = raw_table.get("Values");
    var n = raw_data.length;
    var ranks = new Array(n_variables);
    var base = new Array(n_variables);
    for (var c = 0; c < n_variables; c++) {
        ranks[c] = 0;
        base[c] = 0;
    }
    var sum = new Array(n_variables);
    for (var i = 0; i < n; i++) {
        var respondent_data = raw_data[i];
        var values = sortValues(respondent_data);
        var n_values = values.length;
        var rank_lookup = new Array(n_values);
        var position = 0;
        while (position < n_values) {
            var n_ties = 1;
            while(values[position] == values[position + n_ties] && position + n_ties < n_values)
                n_ties++;
            var rank = average_rank ? position + (n_ties + 1) / 2 : position + 1;
            for (var tie = 0; tie < n_ties; tie++) {
                rank_lookup[position + tie] = rank;
            }
            position += n_ties;
        }
        //alert(respondent_data + " " + not_duplicate + " " + rank_lookup + " " + values);
        if(!reverse) 
            for(var c = 0; c < n_values; c++) 
                rank_lookup[c] = n_non_NET + 1 - rank_lookup[c];
        var respondent_ranks = new Array(n_variables);
        for(var c = 0; c < n_variables; c++) {
            var v = respondent_data[c];
            if(not_duplicate[c] && !isNaN(v))
                respondent_ranks[c] = rank_lookup[values.indexOf(v)];
        }
        // Computing the average acroess respondents. NB: can be optimized by including in previous loop.    
        if (wgt == null) {
            for (var c = 0; c < n_variables; c++) {
                var r = respondent_ranks[c];
                if (r != null) { 
                    base[c]++;
                    ranks[c] += r;
                }
            }
        } else {
            var w = wgt[i]; 
            for (var c = 0; c < n_variables; c++) {
                var r = respondent_ranks[c];
                if (r != null) { 
                    base[c] += w;
                    ranks[c] += r * w;
                }
            }
        }
    }

     
    //Adding to table
    var table_data = table.get(statistic_to_replace);
    for (var c = 0; c < n_variables; c++) 
        table_data[c][0] = ranks[c] / base[c]; 
    table.set(statistic_to_replace, table_data);
     
    // Adding statisic
    // Get the existing statistics on the table (selected by the context menu).
    var stats = table.statistics;
    if (stats.indexOf(statistic_to_replace) == -1)
        stats.push(statistic_to_replace);
    table.statistics = stats;
    form.setTranslation(statistic_to_replace, "Average Rank");
}

See also