Development:Quiz Item Analysis of Multianswers Question Types
This page described a code proposal to access the embedded questions data in multianswers questiion types so that they can be displayed in the Item analysis report. See http://moodle.org/mod/forum/discuss.php?d=86598#387154
The code is experimental and need more testing and is not optimized.
All question types to be analyzed contain at least one embedded question
If we set this as a general framework, the code will be valid for all question types.
We need a question type function to retrieve the embedded questions
There is actually no question type function to know the number the embedded questions in a question. The default function number_of_embedded_questions() returns 1;
This is not the same as actual_number_of_questions().
We need a convention of how to store the responses from the different embedded questions
The same convention should be used in the $session states and in the get_responses function. The actual responses convention used an array to contains the different answers and put in [''] element the actual response. an example for a numerical question with the tolerance limit
stdClass Object
(
[id] => 2312
[responses] => Array
(
[6837] => stdClass Object
(
[answer] => 1822 (1817..1827)
[credit] => 1
)
)
)
In a multianswers qtype the different answers responses are stored in an array as.
stdClass Object
(
[id] => 2815
[responses] => Array
(
[1] => stdClass Object
(
[id] => 2816
[responses] => Array
(
[7300] => stdClass Object
(
[answer] => Wrong answer
[credit] => 0
)
[7302] => stdClass Object
(
[answer] => Correct answer
[credit] => 1
)
[7305] => stdClass Object
(
[answer] => Answer that gives half the credit
[credit] => 0.5
)
)
)
[2] => stdClass Object
(
[id] => 2817
[responses] => Array
(
[7303] => stdClass Object
(
[answer] => Wrong answer
[credit] => 0
)
[7304] => stdClass Object
(
[answer] => Correct answer
[credit] => 1
)
)
)
[3] => stdClass Object
(
[id] => 2818
[responses] => Array
(
[7307] => stdClass Object
(
[answer] => 65 (64.9..65.1)
[credit] => 1
)
)
)
)
)
So the one question question types responses is tranformed in a similar structure.
The upper example becomes
stdClass Object
(
[id] => 2312
[responses] => Array
(
[0] => stdClass Object
(
[id] => 2312
[responses] => Array
(
[6837] => stdClass Object
(
[answer] => 1822 (1817..1827)
[credit] => 1
)
)
)
)
)
The new array elements the defined the responses of the embedded questions and are put in the questions array as subquestions
foreach ($q->responses as $subquestion => $qresponses ){
foreach ($qresponses->responses as $answer => $r) {
$r->count = 0;
$questions[$qid]['subquestion'][$subquestion]['responses'][$answer] = $r->answer;
$questions[$qid]['subquestion'][$subquestion]['rcounts'][$answer] = 0;
$questions[$qid]['subquestion'][$subquestion]['credits'][$answer] = $r->credit;
$statsrow[$qid]['subquestion'][$subquestion] = 0;
}
For a 1 embedded question question type there is just one subquestion with a $subquestion value of 0.
Check response of each subquestion instead of each question
foreach ($responses as $subquestion => $resp ){
if ($resp) {
if ($key = array_search($resp, $questions[$qid]['subquestion'][$subquestion]['responses'])) {
$questions[$qid]['subquestion'][$subquestion]['rcounts'][$key]++;
} else {
$test = new stdClass;
$test->responses = $QTYPES[$quizquestions[$i]->qtype]->get_correct_responses($quizquestions[$i], $states[$i]);
$test->resp = $resp ;
$test->keyresp = $subquestion ;
$test->question_qid = &$questions[$qid] ;
if ($key = $QTYPES[$quizquestions[$i]->qtype]->check_response($quizquestions[$i], $states[$i], $test))
The check_response of a multianswer question type will use the $subquestion to check the $test->resp agains the correct $states response as the $subquestion values where obtained from the multianswer question. The only requirement is that the multianswer use the same convention in get_all_responses that it uses to create the $states data. For one embeded question types the $subquestion ( 0) is ignored as there is no array in the $states data. The result is stored using the same subquestion convention
{
$questions[$qid]['subquestion'][$subquestion]['rcounts'][$key]++;
} else {
$questions[$qid]['subquestion'][$subquestion]['responses'][] = $resp;
$questions[$qid]['subquestion'][$subquestion]['rcounts'][] = 1;
$questions[$qid]['subquestion'][$subquestion]['credits'][] = 0;
}
}
}
}
The multianswer should divide the question text in each embedded questions
We need a new questiontype function that will format the question text and return it in an array of the emmbedded questions text ordered as the responses. The default for 1 embedded question is an unique array element.
$qtext1 = $QTYPES[$question->qtype]->print_question_formulation($question, $format_options, $quiz->course) ;
that is used as
$qtext = $qquestion = $qname."\n".$qtext1[0]."\n";
for the first line of a question display. A typical output for a multianswers
Array ( [0] => This question consists of some text with an answer embedded right here [1] => .Then you will have to deal with this short answer [2] => and finally we have a floating point number age )
The table is built also on the subquestion structure
foreach ($q['subquestion']as $key => $qr ){
foreach ($qr['responses'] as $aid=>$resp){
$response = new stdClass;
if ($qr['credits'][$aid] <= 0) {
$qclass = 'uncorrect';
} elseif ($qr['credits'][$aid] == 1) {
$qclass = 'correct';
} else {
$qclass = 'partialcorrect';
}
$response->credit = '('.format_float($qr['credits'][$aid],2).') ';
$response->text = ''.format_text($resp, FORMAT_MOODLE, $format_options, $quiz->course).' ';
$count = $qr['rcounts'][$aid].'/'.$q['count'];
$response->rcount = $count;
$response->rpercent = '('.format_float($qr['rcounts'][$aid]/$q['count']*100,0).'%)';
$responses[$subindex][] = $response;
}
$subindex++;
}
$facility = format_float($q['facility']*100,0)."%";
$qsd = format_float($q['qsd'],3);
$di = format_float($q['disc_index'],2);
$dc = format_float($q['disc_coeff'],2);
$response = array_shift($responses[0]);
$table->add_data(array($qnumber."\n
".$qicon."\n ".$qreview, $qquestion, $response->text, $response->credit, $response->rcount, $response->rpercent, $facility, $qsd, $di, $dc));
foreach($responses[0] as $response) {
$table->add_data(array(, , $response->text, $response->credit, $response->rcount, $response->rpercent, , , , ));
}
if($subindex >1) {
for($i = 1 ; $i < $subindex ; $i++){
$response = array_shift($responses[$i]);
$table->add_data(array(, $qtext1[$i], $response->text, $response->credit, $response->rcount, $response->rpercent, , , , ));
foreach($responses[$i] as $response) {
$table->add_data(array(, , $response->text, $response->credit, $response->rcount, $response->rpercent, , , , ));
}
}
}
}
