Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Quiz Item Analysis of Multianswers Question Types: Difference between revisions

From MoodleDocs
 
(8 intermediate revisions by the same user not shown)
Line 1: Line 1:
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.
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
See http://moodle.org/mod/forum/discuss.php?d=86598#387154
The code is experimental and need more testing and is not optimized.
The code is experimental and need more testing and is not optimized.
==All question types to be analyzed contain at least one embedded question==
==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.
If we set this as a general framework, the code will be valid for all question types.
Line 84: Line 86:
         )
         )
  )
  )
So the one question question types responses is tranformed in a similar structure
So the one question question types responses is tranformed in a similar structure.
 
The upper example becomes
The upper example becomes
  stdClass Object
  stdClass Object
Line 105: Line 108:
         )
         )
  )
  )
To distinguish
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 = '<span class="'.$qclass.'">('.format_float($qr['credits'][$aid],2).') </span>';
                $response->text = '<span class="'.$qclass.'">'.format_text($resp, FORMAT_MOODLE, $format_options, $quiz->course).' </span>';
                $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<br />".$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, '', '', '', ''));
                    }
                }
            }
                   
        }
==A simple example==
[[image:Item analysis example.jpg]]

Latest revision as of 04:23, 8 January 2008

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, , , , )); } } } }

A simple example

Item analysis example.jpg