Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * Question behaviour type for deferred feedback with CBM behaviour.
19
 *
20
 * @package    qbehaviour_deferredcbm
21
 * @copyright  2012 The Open University
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
 
26
defined('MOODLE_INTERNAL') || die();
27
 
28
require_once(__DIR__ . '/../deferredfeedback/behaviourtype.php');
29
 
30
 
31
/**
32
 * Question behaviour type information for deferred feedback with CBM behaviour.
33
 *
34
 * @copyright  2012 The Open University
35
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36
 */
37
class qbehaviour_deferredcbm_type extends qbehaviour_deferredfeedback_type {
38
    public function adjust_random_guess_score($fraction) {
39
        return question_cbm::adjust_fraction($fraction, question_cbm::default_certainty());
40
    }
41
 
42
    public function summarise_usage(question_usage_by_activity $quba, question_display_options $options) {
43
        global $OUTPUT;
44
        $summarydata = parent::summarise_usage($quba, $options);
45
 
46
        if ($options->marks < question_display_options::MARK_AND_MAX) {
47
            return $summarydata;
48
        }
49
 
50
        // Prepare accumulators to hold the data we are about to collect.
51
        $notansweredcount  = 0;
52
        $notansweredweight = 0;
53
        $attemptcount = array(
54
            question_cbm::HIGH => 0,
55
            question_cbm::MED  => 0,
56
            question_cbm::LOW  => 0,
57
        );
58
        $totalweight = array(
59
            question_cbm::HIGH => 0,
60
            question_cbm::MED  => 0,
61
            question_cbm::LOW  => 0,
62
        );
63
        $totalrawscore = array(
64
            question_cbm::HIGH => 0,
65
            question_cbm::MED  => 0,
66
            question_cbm::LOW  => 0,
67
        );
68
        $totalcbmscore = array(
69
            question_cbm::HIGH => 0,
70
            question_cbm::MED  => 0,
71
            question_cbm::LOW  => 0,
72
        );
73
 
74
        // Loop through the data, and add it to the accumulators.
75
        foreach ($quba->get_attempt_iterator() as $qa) {
76
            if (strpos($qa->get_behaviour_name(), 'cbm') === false || $qa->get_max_mark() < 0.0000005) {
77
                continue;
78
            }
79
 
80
            $gradedstep = $qa->get_last_step_with_behaviour_var('_rawfraction');
81
 
82
            if (!$gradedstep->has_behaviour_var('_rawfraction')) {
83
                $notansweredcount  += 1;
84
                $notansweredweight += $qa->get_max_mark();
85
                continue;
86
            }
87
 
88
            $certainty = $qa->get_last_behaviour_var('certainty');
89
            if (is_null($certainty) || $certainty == -1) {
90
                // Certainty -1 has never been used in standard Moodle, but is
91
                // used in Tony-Gardiner Medwin's patches to mean 'No idea' which
92
                // we intend to implement: MDL-42077. In the mean time, avoid
93
                // errors for people who have used TGM's patches.
94
                $certainty = question_cbm::default_certainty();
95
            }
96
 
97
            $attemptcount[$certainty]  += 1;
98
            $totalweight[$certainty]   += $qa->get_max_mark();
99
            $totalrawscore[$certainty] += $qa->get_max_mark() * $gradedstep->get_behaviour_var('_rawfraction');
100
            $totalcbmscore[$certainty] += $qa->get_mark();
101
        }
102
 
103
        // Hence compute some statistics.
104
        $totalquestions   = $notansweredcount + array_sum($attemptcount);
105
        $grandtotalweight = $notansweredweight + array_sum($totalweight);
106
        $accuracy         = array_sum($totalrawscore) / $grandtotalweight;
107
        $averagecbm       = array_sum($totalcbmscore) / $grandtotalweight;
108
        $cbmbonus         = $this->calculate_bonus($averagecbm, $accuracy);
109
        $accuracyandbonus = $accuracy + $cbmbonus;
110
 
111
        // Add a note to explain the max mark.
112
        $summarydata['qbehaviour_cbm_grade_explanation'] = array(
113
            'title' => '',
114
            'content' => html_writer::tag('i', get_string('cbmgradeexplanation', 'qbehaviour_deferredcbm')) .
115
                    $OUTPUT->help_icon('cbmgrades', 'qbehaviour_deferredcbm'),
116
        );
117
 
118
        // Now we can start generating some of the summary: overall values.
119
        $summarydata['qbehaviour_cbm_entire_quiz_heading'] = array(
120
            'title' => '',
121
            'content' => html_writer::tag('h3',
122
                    get_string('forentirequiz', 'qbehaviour_deferredcbm', $totalquestions),
123
                    array('class' => 'qbehaviour_deferredcbm_summary_heading')),
124
        );
125
        $summarydata['qbehaviour_cbm_entire_quiz_cbm_average'] = array(
126
            'title' => get_string('averagecbmmark', 'qbehaviour_deferredcbm'),
127
            'content' => format_float($averagecbm, $options->markdp),
128
        );
129
        $summarydata['qbehaviour_cbm_entire_quiz_accuracy'] = array(
130
            'title' => get_string('accuracy', 'qbehaviour_deferredcbm'),
131
            'content' => $this->format_probability($accuracy, 1),
132
        );
133
        $summarydata['qbehaviour_cbm_entire_quiz_cbm_bonus'] = array(
134
            'title' => get_string('cbmbonus', 'qbehaviour_deferredcbm'),
135
            'content' => $this->format_probability($cbmbonus, 1),
136
        );
137
        $summarydata['qbehaviour_cbm_entire_quiz_accuracy_and_bonus'] = array(
138
            'title' => get_string('accuracyandbonus', 'qbehaviour_deferredcbm'),
139
            'content' => $this->format_probability($accuracyandbonus, 1),
140
        );
141
 
142
        if ($notansweredcount && array_sum($attemptcount) > 0) {
143
            $totalquestions   = array_sum($attemptcount);
144
            $grandtotalweight = array_sum($totalweight);
145
            $accuracy         = array_sum($totalrawscore) / $grandtotalweight;
146
            $averagecbm       = array_sum($totalcbmscore) / $grandtotalweight;
147
            $cbmbonus         = $this->calculate_bonus($averagecbm, $accuracy);
148
            $accuracyandbonus = $accuracy + $cbmbonus;
149
 
150
            $summarydata['qbehaviour_cbm_answered_quiz_heading'] = array(
151
                'title' => '',
152
                'content' => html_writer::tag('h3',
153
                        get_string('foransweredquestions', 'qbehaviour_deferredcbm', $totalquestions),
154
                        array('class' => 'qbehaviour_deferredcbm_summary_heading')),
155
            );
156
            $summarydata['qbehaviour_cbm_answered_quiz_cbm_average'] = array(
157
                'title' => get_string('averagecbmmark', 'qbehaviour_deferredcbm'),
158
                'content' => format_float($averagecbm, $options->markdp),
159
            );
160
            $summarydata['qbehaviour_cbm_answered_quiz_accuracy'] = array(
161
                'title' => get_string('accuracy', 'qbehaviour_deferredcbm'),
162
                'content' => $this->format_probability($accuracy, 1),
163
            );
164
            $summarydata['qbehaviour_cbm_answered_quiz_cbm_bonus'] = array(
165
                'title' => get_string('cbmbonus', 'qbehaviour_deferredcbm'),
166
                'content' => $this->format_probability($cbmbonus, 1),
167
            );
168
            $summarydata['qbehaviour_cbm_answered_quiz_accuracy_and_bonus'] = array(
169
                'title' => get_string('accuracyandbonus', 'qbehaviour_deferredcbm'),
170
                'content' => $this->format_probability($accuracyandbonus, 1),
171
            );
172
        }
173
 
174
        // Now per-certainty level values.
175
        $summarydata['qbehaviour_cbm_judgement_heading'] = array(
176
            'title' => '',
177
            'content' => html_writer::tag('h3', get_string('breakdownbycertainty', 'qbehaviour_deferredcbm'),
178
                    array('class' => 'qbehaviour_deferredcbm_summary_heading')),
179
        );
180
 
181
        foreach ($attemptcount as $certainty => $count) {
182
            $key   = 'qbehaviour_cbm_judgement' . $certainty;
183
            $title = question_cbm::get_short_string($certainty);
184
 
185
            if ($count == 0) {
186
                $summarydata[$key] = array(
187
                    'title' => $title,
188
                    'content' => get_string('noquestions', 'qbehaviour_deferredcbm'),
189
                );
190
                continue;
191
            }
192
 
193
            $lowerlimit = question_cbm::optimal_probablility_low($certainty);
194
            $upperlimit = question_cbm::optimal_probablility_high($certainty);
195
            $fraction = $totalrawscore[$certainty] / $totalweight[$certainty];
196
 
197
            $a = new stdClass();
198
            $a->responses = $count;
199
            $a->idealrangelow  = $this->format_probability($lowerlimit);
200
            $a->idealrangehigh = $this->format_probability($upperlimit);
201
            $a->fraction       = html_writer::tag('span', $this->format_probability($fraction),
202
                    array('class' => 'qbehaviour_deferredcbm_actual_percentage'));
203
 
204
            if ($fraction < $lowerlimit - 0.0000005) {
205
                if ((pow($fraction - $lowerlimit, 2) * $count) > 0.5) { // Rough indicator of significance: t > 1.5 or 1.8.
206
                    $judgement = 'overconfident';
207
                } else {
208
                    $judgement = 'slightlyoverconfident';
209
                }
210
            } else if ($fraction > $upperlimit + 0.0000005) {
211
                if ((pow($fraction - $upperlimit, 2) * $count) > 0.5) {
212
                    $judgement = 'underconfident';
213
                } else {
214
                    $judgement = 'slightlyunderconfident';
215
                }
216
            } else {
217
                $judgement = 'judgementok';
218
            }
219
            $a->judgement = html_writer::tag('span', get_string($judgement, 'qbehaviour_deferredcbm'),
220
                    array('class' => 'qbehaviour_deferredcbm_' . $judgement));
221
 
222
            $summarydata[$key] = array(
223
                'title' => $title,
224
                'content' => get_string('judgementsummary', 'qbehaviour_deferredcbm', $a),
225
            );
226
        }
227
 
228
        return $summarydata;
229
    }
230
 
231
    protected function format_probability($probability, $dp = 0) {
232
        return format_float($probability * 100, $dp) . '%';
233
    }
234
 
235
    public function calculate_bonus($total, $accuracy) {
236
        $expectedforaccuracy = max(
237
            $accuracy * question_cbm::adjust_fraction(1, question_cbm::LOW) +
238
                (1 - $accuracy) * question_cbm::adjust_fraction(0, question_cbm::LOW),
239
            $accuracy * question_cbm::adjust_fraction(1, question_cbm::MED) +
240
                (1 - $accuracy) * question_cbm::adjust_fraction(0, question_cbm::MED),
241
            $accuracy * question_cbm::adjust_fraction(1, question_cbm::HIGH) +
242
                (1 - $accuracy) * question_cbm::adjust_fraction(0, question_cbm::HIGH)
243
        );
244
        // The constant 0.1 here is determinted empirically from looking at lots
245
        // for CBM quiz results. See www.ucl.ac.uk/~ucgbarg/tea/IUPS_2013a.pdf.
246
        // It approximately maximises the reliability of accuracy + bonus.
247
        return 0.1 * ($total - $expectedforaccuracy);
248
    }
249
}