QScript Functions for Binary Variables
Jump to navigation
Jump to search
This page is currently under construction, or it refers to features which are under development and not yet available for use.
This page is under construction. Its contents are only visible to developers!
includeWeb("QScript Functions to Generate Outputs");
includeWeb("QScript R Output Functions");
includeWeb("QScript R Variable Creation Functions");
includeWeb("QScript Selection Functions");
includeWeb("QScript Utility Functions");
function getVariableOrQuestionLabel(variable) {
if (/- Multi|- Grid/.test(variable.question.variableSetStructure)) {
return variable.question.name;
}
return variable.label.length > 0 ? variable.label : variable.name;
}
function numericQuestionsToBinary(questions) {
const is_displayr = inDisplayr();
const variables = getVariablesFromQuestions(questions);
const data_file = variables[0].question.dataFile;
const suitable_for_grid = suitableForGrid(questions);
const make_grid = (questions.length > 1 && suitable_for_grid) || (questions.length === 1 && suitable_for_grid && questions[0].questionType === "Number - Grid");
let variable_labels = variables.map((v) => v.label);
const is_variable_labels_duplicated = variable_labels.length !== new Set(variable_labels).size;
if (make_grid || is_variable_labels_duplicated) {
variable_labels = variables.map((v, v_ind) => v.question.name + " - " + variable_labels[v_ind]);
}
const base_question_name = preventDuplicateQuestionName(data_file, variable_labels.filter(onlyUnique).join(" + "));
const r_variable_name = variables.length === 1 ? "x" : "variable.set";
const last_variable = getLastVariable(variables);
const temp_var_name = randomVariableName(16); // temporary name, random to (almost) guarantee uniqueness
const variable_names = variables.map((v) => checkDuplicateVariable(v.name) ? generateDisambiguatedVariableName(v) : stringToRName(v.name));
// Simple assignment if single variable, otherwise data.frame
let expression;
if (variables.length === 1) {
expression = r_variable_name + ' <- ' + variable_names + '\n';
}
else {
const df_assignments = [];
for (let i = 0; i < variables.length; i += 1) {
df_assignments[i] = stringToRName(variable_labels[i]) + " = " + variable_names[i];
}
const def_prefix = r_variable_name + ' <- data.frame(';
const white_spaces = " ".repeat(def_prefix.length);
expression = def_prefix + df_assignments.join(",\n" + white_spaces) + ',\n' + white_spaces + 'check.names = FALSE)\n';
}
expression += "binary.var = " + r_variable_name + " > 0\n" +
"# If you wish to change the cut-off for the count (from > 0), modify the code above\n" +
"# E.g. To count values larger than 50, change > 0 to > 50\n" +
"# E.g. To count values smaller than or equal to 25, change > 0 to <= 25\n"
+ "binary.var";
checkFileHasMoreThanOneCase(data_file);
try {
const question = robustNewRQuestion(data_file, expression, base_question_name, temp_var_name, last_variable);
question.questionType = make_grid ? "Pick Any - Grid" : "Pick Any";
question.name = preventDuplicateQuestionName(data_file, variables.map((x) => getVariableOrQuestionLabel(x)).filter(onlyUnique).join(" + ") + " > 0");
question.needsCheckValuesToCount = false;
insertAtHoverButtonIfShown(question);
// Replace temporary variable names
nameSequentialVariables(question.variables, "binary");
reportNewRQuestion(question, "Binary transformed question");
}
catch (e) {
const structure_name = getVariableNaming(is_displayr);
log("The binary transform could not be computed for this " + structure_name + ": " + e);
return;
}
}
function categoricalQuestionsToBinary(selected_questions, compute_for_incomplete) {
const data_file = selected_questions[0].dataFile;
checkFileHasMoreThanOneCase(data_file);
// Ensure labels match between questions
const all_labels = getAllCategories(selected_questions);
const r_names = selected_questions.map((x) => generateDisambiguatedQuestionName(x));
const q_name = `Binary variables from: ${selected_questions.map((q) => q.name).join(" + ")}`;
const r_expr = `
library(flipData)
n.categories <- ${all_labels.length}
binary.data <- CombineVariableSetsAsBinary(${r_names.join(", ")}, compute.for.incomplete = ${compute_for_incomplete ? "TRUE" : "FALSE"})
if (ncol(binary.data) != n.categories) {
StopForUserError("The number of categories in the input data has changed. You should re-run the Binary Variables option again.")
}
binary.data
`;
const variables = getVariablesFromQuestions(selected_questions);
const last_variable = getLastVariable(variables);
try {
const new_q = robustNewRQuestion(data_file, r_expr, preventDuplicateQuestionName(data_file, q_name), "binary" + makeid(), last_variable);
new_q.questionType = "Pick Any";
new_q.needsCheckValuesToCount = false;
insertAtHoverButtonIfShown(new_q);
reportNewRQuestion(new_q, "Binary transformed question");
}
catch (e) {
let message = 'Binary variables could not be created for the selected variables. ';
message += e.message;
log(message);
}
}
function getAllCategories(questions) {
const labels = questions.map((q) => {
if (q.questionType.indexOf("Pick One") === 0) {
return getRFactorLevelsFromQuestionOrVariable(q).labels;
}
else if (q.questionType.indexOf("Pick Any") === 0) {
const data_reduction = q.dataReduction;
const net_rows = data_reduction.netRows;
let labels = data_reduction.rowLabels || [];
labels = labels.filter((x, index) => net_rows.indexOf(index) === -1);
return labels;
}
throw new UserError(`${(inDisplayr() ? q.variableSetStructure : q.questionType)} data is not supported.`);
});
const all_labels = [];
labels.forEach((arr) => {
arr.forEach((label) => {
if (all_labels.indexOf(label) === -1)
all_labels.push(label);
});
});
return all_labels;
}
function getVariableNaming(is_displayr) {
return is_displayr ? "variable sets" : "questions";
}
function suitableForGrid(questions) {
// Check each question has the same number of variables
const qvar_names = questions.map((q) => q.variables.map((v) => v.label));
for (let i = 1; i < questions.length; i++) {
if (qvar_names[i].length !== qvar_names[0].length)
return false;
if (!arraysEqual(qvar_names[i], qvar_names[0]))
return false;
}
return true;
}
function binaryVariablesFromValuesGreaterThanZero() {
const allowed_types = [
"Numeric",
"Numeric - Multi",
"Numeric - Grid"
];
const selected_questions = selectInputQuestions(allowed_types);
if (!selected_questions) {
return;
}
const questions_array = Array.isArray(selected_questions) ? selected_questions : [selected_questions];
numericQuestionsToBinary(questions_array);
}
function binaryVariablesFromCategories() {
const allowed_types = [
"Nominal",
"Nominal - Multi",
"Ordinal",
"Ordinal - Multi",
"Binary - Multi",
"Binary - Multi (Compact)"
];
const selected_questions = selectInputQuestions(allowed_types);
if (!selected_questions)
return;
const questions_array = Array.isArray(selected_questions) ? selected_questions : [selected_questions];
let compute_for_incomplete = true;
if (questions_array.length > 1) {
compute_for_incomplete = askYesNo("Compute for cases with incomplete data?");
}
categoricalQuestionsToBinary(questions_array, compute_for_incomplete);
}
function binaryVariables() {
const is_displayr = inDisplayr();
const allowed_types = [
"Nominal",
"Nominal - Multi",
"Numeric",
"Numeric - Multi",
"Numeric - Grid",
"Ordinal",
"Ordinal - Multi",
"Binary - Multi",
"Binary - Multi (Compact)"
];
const selected_questions = selectInputQuestions(allowed_types);
if (!selected_questions)
return;
const questions_array = Array.isArray(selected_questions) ? selected_questions : [selected_questions];
const variable_set_structures = questions_array.map((x) => x.variableSetStructure);
const all_numeric = variable_set_structures.every((x) => /Numeric/.test(x));
const binary_categorical_mix = variable_set_structures.every((x) => /(Nominal|Ordinal|Binary)/.test(x));
if (binary_categorical_mix && Q.fileFormatVersion() < 22.12) {
log("This feature requires a new version of Q. Please contact support@q-researchsoftware.com");
return;
}
if (!(all_numeric || binary_categorical_mix)) {
log(correctTerminology(`Cannot create Binary Variables from this selection of ${is_displayr ? "variable set Structures" : "Question Types"}. Select variables which are all Numeric, all Nominal/Ordinal, or a mix of Binary and Nominal/Ordinal.`));
return;
}
if (all_numeric) {
numericQuestionsToBinary(questions_array);
}
else if (binary_categorical_mix) {
let compute_for_incomplete = true;
if (questions_array.length > 1)
compute_for_incomplete = askYesNo("Compute for cases with incomplete data?");
categoricalQuestionsToBinary(questions_array, compute_for_incomplete);
}
}