Annotation of loncom/interface/statistics/lonproblemstatistics.pm, revision 1.20
1.1 stredwic 1: # The LearningOnline Network with CAPA
2: # (Publication Handler
3: #
1.20 ! stredwic 4: # $Id: lonproblemstatistics.pm,v 1.19 2002/08/13 00:37:18 stredwic Exp $
1.1 stredwic 5: #
6: # Copyright Michigan State University Board of Trustees
7: #
8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
9: #
10: # LON-CAPA is free software; you can redistribute it and/or modify
11: # it under the terms of the GNU General Public License as published by
12: # the Free Software Foundation; either version 2 of the License, or
13: # (at your option) any later version.
14: #
15: # LON-CAPA is distributed in the hope that it will be useful,
16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18: # GNU General Public License for more details.
19: #
20: # You should have received a copy of the GNU General Public License
21: # along with LON-CAPA; if not, write to the Free Software
22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23: #
24: # /home/httpd/html/adm/gpl.txt
25: #
26: # http://www.lon-capa.org/
27: #
28: # (Navigate problems for statistical reports
29: # YEAR=2001
30: # 5/5,7/9,7/25/1,8/11,9/13,9/26,10/5,10/9,10/22,10/26 Behrouz Minaei
31: # 11/1,11/4,11/16,12/14,12/16,12/18,12/20,12/31 Behrouz Minaei
32: # YEAR=2002
33: # 1/22,2/1,2/6,2/25,3/2,3/6,3/17,3/21,3/22,3/26,4/7,5/6 Behrouz Minaei
1.12 minaeibi 34: # 5/12,5/14,5/15,5/19,5/26,7/16,7/25,7/29,8/5 Behrouz Minaei
1.1 stredwic 35: #
36: ###
37:
38: package Apache::lonproblemstatistics;
39:
40: use strict;
41: use Apache::lonnet();
42: use Apache::lonhtmlcommon;
43: use Apache::loncoursedata;
44: use GDBM_File;
45:
1.19 stredwic 46: my $jr;
1.1 stredwic 47:
48: sub BuildProblemStatisticsPage {
1.5 minaeibi 49: my ($cacheDB, $students, $courseID, $c, $r)=@_;
1.1 stredwic 50: my %cache;
1.16 minaeibi 51:
1.19 stredwic 52: $jr = $r;
53:
1.18 albertel 54: unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
1.1 stredwic 55: return '<html><body>Unable to tie database.</body></html>';
56: }
57:
58: my $Ptr = '';
59: $Ptr .= '<table border="0"><tbody>';
60: $Ptr .= '<tr><td align="right"><b>Select Map</b></td>'."\n";
61: $Ptr .= '<td align="left">';
1.9 stredwic 62: $Ptr .= &Apache::lonhtmlcommon::MapOptions(\%cache, 'ProblemStatistics',
63: 'Statistics');
64: $Ptr .= '</td></tr>'."\n";
65: $Ptr .= '<tr><td align="right"><b>Sorting Type:</b></td>'."\n";
66: $Ptr .= '<td align="left">'."\n";
67: $Ptr .= &Apache::lonhtmlcommon::AscendOrderOptions(
68: $cache{'ProblemStatisticsAscend'},
69: 'ProblemStatistics',
70: 'Statistics');
1.1 stredwic 71: $Ptr .= '</td></tr>'."\n";
1.20 ! stredwic 72: $Ptr .= &ProblemStatisticsButtons($cache{'DisplayFormat'},
! 73: $cache{'DisplayLegend'});
1.2 minaeibi 74: $Ptr .= '</table>';
1.20 ! stredwic 75: if($cache{'DisplayLegend'} eq 'Show Legend') {
! 76: $Ptr .= &ProblemStatisticsLegend();
! 77: }
1.5 minaeibi 78: $r->print($Ptr);
1.13 stredwic 79: $r->rflush();
1.1 stredwic 80:
81: untie(%cache);
1.19 stredwic 82:
83: &Apache::loncoursedata::DownloadStudentCourseDataSeparate($students,'true',
84: $cacheDB,'true',
85: 'true',$courseID,
86: $r, $c);
1.5 minaeibi 87: if($c->aborted()) { return; }
1.1 stredwic 88:
1.18 albertel 89: unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
1.1 stredwic 90: return '<html><body>Unable to tie database.</body></html>';
91: }
1.12 minaeibi 92:
1.19 stredwic 93: my @Header = ("Homework Sets Order","#Stdnts","Tries","Mod",
94: "Mean","#YES","#yes","%Wrng","DoDiff",
95: "S.D.","Skew.","D.F.1st","D.F.2nd","Disc.");
1.5 minaeibi 96: my $color=&setbgcolor(0);
1.12 minaeibi 97:
1.19 stredwic 98: # my %Discuss=&Apache::loncoursedata::LoadDiscussion($courseID);
99: # my ($upper, $lower) = &Discriminant(\%discriminant,$r);
100: my ($problemData) = &ExtractStudentData(\%cache, $students);
101: &CalculateStatistics($problemData);
102: &SortProblems($problemData, $cache{'ProblemStatisticsSort'},
103: $cache{'ProblemStatisticsAscend'});
104: #$TempCache=
105: &BuildStatisticsTable(\%cache, $cache{'DisplayFormat'},
106: $problemData, \@Header, $r, $color);
107: untie(%cache);
1.12 minaeibi 108:
1.19 stredwic 109: # foreach (keys %$TempCache) {
110: # last if ($c->aborted());
111: # if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
112: # $cache{$_}=$TempCache->{$_};
113: # untie(%cache);
114: # }
115: # }
1.12 minaeibi 116:
1.19 stredwic 117: # if($c->aborted()) { return; }
118: # untie(%cache);
1.12 minaeibi 119:
1.19 stredwic 120: return;
1.1 stredwic 121: }
122:
123:
124: #---- Problem Statistics Web Page ---------------------------------------
125:
126: sub CreateProblemStatisticsTableHeading {
1.19 stredwic 127: my ($headings,$r)=@_;
1.3 minaeibi 128:
1.19 stredwic 129: my $Str='';
130: $Str .= '<tr>'."\n";
131: $Str .= '<th bgcolor="#ffffe6">P#</th>'."\n";
132: foreach(@$headings) {
133: $Str .= '<th bgcolor="#ffffe6">'.'<a href="/adm/statistics?reportSelected=';
134: $Str .= &Apache::lonnet::escape('Problem Statistics');
135: $Str .= '&ProblemStatisticsSort=';
136: $Str .= &Apache::lonnet::escape($_).'">'.$_.'</a> </th>'."\n";
1.1 stredwic 137: }
1.19 stredwic 138: $Str .= "\n".'</tr>'."\n";
1.1 stredwic 139:
1.19 stredwic 140: return $Str;
1.1 stredwic 141: }
1.12 minaeibi 142:
1.1 stredwic 143: sub BuildStatisticsTable {
1.19 stredwic 144: my ($cache,$displayFormat,$data,$headings,$r,$color)=@_;
1.5 minaeibi 145:
1.1 stredwic 146: #6666666
147: # my $file="/home/httpd/perl/tmp/183d.txt";
148: # open(OUT, ">$file");
149: #6666666
1.2 minaeibi 150: ## &Apache::lonstatistics::Create_PrgWin($r);
1.1 stredwic 151: ##777777
152: ## my (%Activity) = &LoadActivityLog();
153: ## $r->print('<script>popwin.document.popremain.remaining.value="'.
154: ## 'Loading Discussion...";</script>');
155: ## my ($doDiffFile) = &LoadDoDiffFile();
156:
1.5 minaeibi 157: ##777777
158: ## $Str .= &Classify($discriminantFactor, $students);
159:
1.12 minaeibi 160: my %TempCache;
1.19 stredwic 161: my $problems = $data->{'problemList'};
162: if($displayFormat ne 'Display CSV Format') {
163: $r->print('<table border="0"><tr><td bgcolor="#777777">'."\n");
164: $r->print('<table border="0" cellpadding="3">'."\n");
165: $r->print(&CreateProblemStatisticsTableHeading($headings, $r));
166: } else {
167: $r->print('<br>');
168: }
1.1 stredwic 169:
1.19 stredwic 170: my $count = 1;
171: foreach(@$problems) {
172: my ($sequence,$problem,$part)=split(':', $_);
173: # my $problemRef = '<a href="'.$cache->{$problem.':source'}.
174: # '" target="_blank">'.$cache->{$problem.':title'}.'</a>';
175:
176: my $ref = $cache->{$problem.':title'};
177: my $title = $cache->{$problem.':title'};
178: my $source = 'source';
179: my $tableData = join('&', $ref, $title, $source,
180: $data->{$_.':studentCount'},
181: $data->{$_.':totalTries'},
182: $data->{$_.':maxTries'},
183: sprintf("%.2f", $data->{$_.':mean'}),
184: $data->{$_.':correct'},
185: $data->{$_.':correctByOverride'},
186: sprintf("%.1f", $data->{$_.':percentWrong'}),
187: sprintf("%.2f", $data->{$_.':degreeOfDifficulty'}),
188: sprintf("%.1f", $data->{$_.':standardDeviation'}),
189: sprintf("%.1f", $data->{$_.':skewness'}),
190: sprintf("%.2f", $data->{$_.':discriminationFactor1'}),
191: sprintf("%.2f", $data->{$_.':discriminationFactor2'}),
192: 0); # 0 is for discussion, need to figure out
193: # $TempCache{'CacheTable:'.$_}=$join;
1.1 stredwic 194:
195: #6666666
196: # $r->print('<br>'.$out.'&'.$DoD);
197: # print (OUT $out.'@'.$DoD.'&');
198: #6666666
199:
1.16 minaeibi 200: #check with Gerd
1.19 stredwic 201: # $urlres=~/^(\w+)\/(\w+)/;
202: # if ($StdNo) {
203: # &Apache::lonnet::put('nohist_resevaldata',\%storestats,
204: # $1,$2);
205: # }
1.1 stredwic 206: #-------------------------------- Row of statistical table
1.19 stredwic 207: &TableRow($displayFormat,$tableData,$count,$r,$color);
208: # $GraphDat->{'GraphGif:'.($count-1)}=$DoD.':'.$Wrng;
209: $count++;
210: }
211: # $TempCache{'ProblemCount'}=$count;
212: if($cache->{'DisplayFormat'} ne 'Display CSV Format') {
213: $r->print('</table>'."\n");
1.1 stredwic 214: }
1.19 stredwic 215: $r->print('</td></tr></table>');
1.14 minaeibi 216: #6666666
1.1 stredwic 217: # close( OUT );
218: #666666
1.12 minaeibi 219: return \%TempCache;
1.1 stredwic 220: }
221:
1.19 stredwic 222: =pod
1.12 minaeibi 223: sub CacheStatisticsTable {
1.14 minaeibi 224: my ($state,$cache,$headings,$r,$color)=@_;
225: my @list = ();
1.12 minaeibi 226: my %TempCache;
1.14 minaeibi 227: my %myHeader = reverse( %$headings );
1.12 minaeibi 228: my $pos = $myHeader{$state};
229: if ($pos > 0) {$pos++;}
230: my $p_count = $cache->{'ProblemCount'};
231:
232: for ( my $k=0; $k<$p_count;$k++) {
233: my $key=$cache->{'CacheTable:'.$k};
234: my @Temp=split(/\&/,$key);
1.14 minaeibi 235: $list[$k]=$Temp[$pos].'+'.$key;
236: }
237:
238: if ($pos>0) {
1.15 minaeibi 239: @list = sort OrderedSort (@list);
1.14 minaeibi 240: } else {
241: @list = sort (@list);
1.1 stredwic 242: }
1.14 minaeibi 243: my $cIdx=0;
1.1 stredwic 244:
1.14 minaeibi 245: if ( $pos == 0 ) {
1.12 minaeibi 246: foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
247: if($cache->{'ProblemStatisticsMaps'} ne 'All Maps' &&
248: $cache->{'ProblemStatisticsMaps'} ne $cache->{$sequence.':title'}) {
249: next;
250: }
1.14 minaeibi 251: if ($cIdx==$p_count) {
252: return \%TempCache;
253: }
1.19 stredwic 254: $r->print(&CreateProblemStatisticsTableHeading(
255: $cache->{'DisplayFormat'},
1.12 minaeibi 256: $cache->{$sequence.':source'},
257: $cache->{$sequence.':title'},
1.19 stredwic 258: $headings,$r));
1.12 minaeibi 259:
1.14 minaeibi 260: my ($tar)=split(/\&/,$list[$cIdx]);
261: $tar=~s/\+//eg;
262: my ($SqOrd)=split(/\@/,$tar);
1.12 minaeibi 263: $sequence+=100;
1.14 minaeibi 264: while ($SqOrd==$sequence && $cIdx<$p_count) {
265: my($Pre, $Post) = split(/\+/,$list[$cIdx]);
266: &TableRow($cache,$Post,$cIdx,$cIdx,$r,$color,\%TempCache);
267: $cIdx++;
268: my ($tar)=split(/\&/,$list[$cIdx]);
269: $tar=~s/\+//eg;
270: ($SqOrd)=split(/\@/,$tar);
1.1 stredwic 271: }
1.14 minaeibi 272: &CloseTable($cache,$r);
1.1 stredwic 273: }
274: }
275: else {
1.19 stredwic 276: $r->print(&CreateProblemStatisticsTableHeading(
277: $cache->{'DisplayFormat'},
1.14 minaeibi 278: 'Sorted by: ',
279: $headings->{$pos-1},
1.19 stredwic 280: $headings,$r));
1.1 stredwic 281: for ( my $nIndex = 0; $nIndex < $p_count; $nIndex++ ) {
1.14 minaeibi 282: my($Pre, $Post) = split(/\+/,$list[$nIndex]);
283: &TableRow($cache,$Post,$nIndex,$nIndex,$r,$color,\%TempCache);
1.1 stredwic 284: }
1.14 minaeibi 285: &CloseTable($cache,$r);
1.1 stredwic 286: }
1.12 minaeibi 287:
288: return \%TempCache;
1.1 stredwic 289: }
1.19 stredwic 290: =cut
1.1 stredwic 291:
292: sub TableRow {
1.19 stredwic 293: my ($displayFormat,$Str,$RealIdx,$r,$color)=@_;
294: my($ref,$title,$source,$StdNo,$TotalTries,$MxTries,$Avg,$YES,$Override,
1.1 stredwic 295: $Wrng,$DoD,$SD,$Sk,$_D1,$_D2,$DiscNo,$Prob)=split(/\&/,$Str);
1.8 minaeibi 296: my $Ptr;
1.19 stredwic 297: if($displayFormat eq 'Display CSV Format') {
1.8 minaeibi 298: $Ptr="\n".'<br>'.
1.19 stredwic 299: "\n".'"'.$RealIdx.'",'.
300: "\n".'"'.$title.'",'.
301: "\n".'"'.$source.'",'.
1.8 minaeibi 302: "\n".'"'.$StdNo.'",'.
303: "\n".'"'.$TotalTries.'",'.
304: "\n".'"'.$MxTries.'",'.
305: "\n".'"'.$Avg.'",'.
306: "\n".'"'.$YES.'",'.
307: "\n".'"'.$Override.'",'.
308: "\n".'"'.$Wrng.'",'.
309: "\n".'"'.$DoD.'",'.
310: "\n".'"'.$SD.'",'.
311: "\n".'"'.$Sk.'",'.
312: "\n".'"'.$_D1.'",'.
313: "\n".'"'.$_D2.'"'.
314: "\n".'"'.$DiscNo.'"';
1.1 stredwic 315:
316: $r->print("\n".$Ptr);
1.8 minaeibi 317: } else {
318: $Ptr="\n".'<tr>'.
1.19 stredwic 319: "\n".'<td bgcolor="#ffffe6">'.$RealIdx.'</td>'.
320: "\n".'<td bgcolor="#ffffe6">'.$ref.'</td>'.
1.8 minaeibi 321: "\n".'<td bgcolor='.$color->{"yellow"}.'> '.$StdNo.'</td>'.
322: "\n".'<td bgcolor='.$color->{"yellow"}.'>'.$TotalTries.'</td>'.
323: "\n".'<td bgcolor='.$color->{"yellow"}.'>'.$MxTries.'</td>'.
324: "\n".'<td bgcolor='.$color->{"gb"}.'>'.$Avg.'</td>'.
325: "\n".'<td bgcolor='.$color->{"gb"}.'> '.$YES.'</td>'.
326: "\n".'<td bgcolor='.$color->{"gb"}.'> '.$Override.'</td>'.
327: "\n".'<td bgcolor='.$color->{"red"}.'> '.$Wrng.'</td>'.
328: "\n".'<td bgcolor='.$color->{"red"}.'> '.$DoD.'</td>'.
329: "\n".'<td bgcolor='.$color->{"green"}.'> '.$SD.'</td>'.
330: "\n".'<td bgcolor='.$color->{"green"}.'> '.$Sk.'</td>'.
331: "\n".'<td bgcolor='.$color->{"purple"}.'> '.$_D1.'</td>'.
332: "\n".'<td bgcolor='.$color->{"purple"}.'> '.$_D2.'</td>'.
333: "\n".'<td bgcolor='.$color->{"yellow"}.'> '.$DiscNo.'</td>';
1.1 stredwic 334: $r->print("\n".$Ptr.'</tr>' );
335: }
1.19 stredwic 336:
337: return;
1.1 stredwic 338: }
1.5 minaeibi 339:
340: # For loading the colored table for display or un-colored for print
341: sub setbgcolor {
342: my $PrintTable=shift;
343: my %color;
344: if ($PrintTable){
345: $color{"gb"}="#FFFFFF";
346: $color{"red"}="#FFFFFF";
347: $color{"yellow"}="#FFFFFF";
348: $color{"green"}="#FFFFFF";
349: $color{"purple"}="#FFFFFF";
350: } else {
351: $color{"gb"}="#DDFFFF";
352: $color{"red"}="#FFDDDD";
353: $color{"yellow"}="#EEFFCC";
354: $color{"green"}="#DDFFDD";
355: $color{"purple"}="#FFDDFF";
356: }
357:
358: return \%color;
359: }
360:
1.1 stredwic 361: sub ProblemStatisticsButtons {
1.20 ! stredwic 362: my ($displayFormat, $displayLegend)=@_;
1.1 stredwic 363:
364: my $Ptr = '<tr><td></td><td align="left">';
365: $Ptr .= '<input type="submit" name="DoDiffGraph" ';
366: $Ptr .= 'value="DoDiff Graph" />'."\n";
367: $Ptr .= ' ';
368: $Ptr .= '<input type="submit" name="PercentWrongGraph" ';
369: $Ptr .= 'value="%Wrong Graph" />'."\n";
1.20 ! stredwic 370: $Ptr .= '</td></tr><tr><td></td><td>'."\n";
! 371: $Ptr .= '<input type="submit" name="DisplayLegend" ';
! 372: if($displayLegend eq 'Show Legend') {
! 373: $Ptr .= 'value="Hide Legend" />'."\n";
! 374: } else {
! 375: $Ptr .= 'value="Show Legend" />'."\n";
! 376: }
1.1 stredwic 377: $Ptr .= ' ';
378: $Ptr .= '<input type="submit" name="DisplayCSVFormat" ';
379: if($displayFormat eq 'Display CSV Format') {
1.9 stredwic 380: $Ptr .= 'value="Display Table Format" />'."\n";
381: } else {
1.1 stredwic 382: $Ptr .= 'value="Display CSV Format" />'."\n";
383: }
384: $Ptr .= '</td></tr>';
385:
386: return $Ptr;
387: }
388:
389: sub ProblemStatisticsLegend {
390: my $Ptr = '';
391: $Ptr = '<table border="0">';
392: $Ptr .= '<tr><td>';
1.6 minaeibi 393: $Ptr .= '<b>#Stdnts</b></td>';
1.19 stredwic 394: $Ptr .= '<td>Total number of students attempted the problem.';
1.1 stredwic 395: $Ptr .= '</td></tr><tr><td>';
1.6 minaeibi 396: $Ptr .= '<b>Tries</b></td>';
1.19 stredwic 397: $Ptr .= '<td>Total number of tries for solving the problem.';
1.1 stredwic 398: $Ptr .= '</td></tr><tr><td>';
1.6 minaeibi 399: $Ptr .= '<b>Mod</b></td>';
1.19 stredwic 400: $Ptr .= '<td>Largest number of tries for solving the problem by a student.';
1.1 stredwic 401: $Ptr .= '</td></tr><tr><td>';
1.6 minaeibi 402: $Ptr .= '<b>Mean</b></td>';
1.19 stredwic 403: $Ptr .= '<td>Average number of tries. [ Tries / #Stdnts ]';
1.1 stredwic 404: $Ptr .= '</td></tr><tr><td>';
1.6 minaeibi 405: $Ptr .= '<b>#YES</b></td>';
1.1 stredwic 406: $Ptr .= '<td>Number of students solved the problem correctly.';
407: $Ptr .= '</td></tr><tr><td>';
1.6 minaeibi 408: $Ptr .= '<b>#yes</b></td>';
1.1 stredwic 409: $Ptr .= '<td>Number of students solved the problem by override.';
410: $Ptr .= '</td></tr><tr><td>';
1.19 stredwic 411: $Ptr .= '<b>%Wrong</b></td>';
412: $Ptr .= '<td>Percentage of students who tried to solve the problem ';
413: $Ptr .= 'but is still incorrect. [ 100*((#Stdnts-(#YES+#yes))/#Stdnts) ]';
1.1 stredwic 414: $Ptr .= '</td></tr><tr><td>';
1.6 minaeibi 415: $Ptr .= '<b>DoDiff</b></td>';
1.1 stredwic 416: $Ptr .= '<td>Degree of Difficulty of the problem. ';
417: $Ptr .= '[ 1 - ((#YES+#yes) / Tries) ]';
418: $Ptr .= '</td></tr><tr><td>';
1.6 minaeibi 419: $Ptr .= '<b>S.D.</b></td>';
1.1 stredwic 420: $Ptr .= '<td>Standard Deviation of the tries. ';
421: $Ptr .= '[ sqrt(sum((Xi - Mean)^2)) / (#Stdnts-1) ';
422: $Ptr .= 'where Xi denotes every student\'s tries ]';
423: $Ptr .= '</td></tr><tr><td>';
1.6 minaeibi 424: $Ptr .= '<b>Skew.</b></td>';
1.1 stredwic 425: $Ptr .= '<td>Skewness of the students tries.';
426: $Ptr .= '[(sqrt( sum((Xi - Mean)^3) / #Stdnts)) / (S.D.^3)]';
427: $Ptr .= '</td></tr><tr><td>';
1.6 minaeibi 428: $Ptr .= '<b>Dis.F.</b></td>';
1.1 stredwic 429: $Ptr .= '<td>Discrimination Factor: A Standard for evaluating the ';
430: $Ptr .= 'problem according to a Criterion<br>';
431: $Ptr .= '<b>[Applied Criterion in %27 Upper Students - ';
432: $Ptr .= 'Applied the same Criterion in %27 Lower Students]</b><br>';
433: $Ptr .= '<b>1st Criterion</b> for Sorting the Students: ';
434: $Ptr .= '<b>Sum of Partial Credit Awarded / Total Number of Tries</b><br>';
435: $Ptr .= '<b>2nd Criterion</b> for Sorting the Students: ';
436: $Ptr .= '<b>Total number of Correct Answers / Total Number of Tries</b>';
437: $Ptr .= '</td></tr>';
438: $Ptr .= '<tr><td><b>Disc.</b></td>';
439: $Ptr .= '<td>Number of Students had at least one discussion.';
440: $Ptr .= '</td></tr></table>';
441:
442: return $Ptr;
443: }
444:
1.4 minaeibi 445: #------- Processing upperlist and lowerlist according to each problem
1.19 stredwic 446:
447: sub ExtractStudentData {
448: my ($cache, $students)=@_;
449:
450: #$Apache::lonxml::debug=1;
451: #&Apache::lonhomework::showhash(%$cache);
452: #$Apache::lonxml::debug=0;
453:
454: my @problemList=();
455: my %problemData;
456: foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
457: if($cache->{'ProblemStatisticsMaps'} ne 'All Maps' &&
458: $cache->{'ProblemStatisticsMaps'} ne $cache->{$sequence.':title'}) {
459: next;
460: }
461:
462: foreach my $problemID (split(':', $cache->{$sequence.':problems'})) {
463: foreach my $part (split(/\:/,$cache->{$sequence.':'.
464: $problemID.
465: ':parts'})) {
466: my $id = $sequence.':'.$problemID.':'.$part;
467: push(@problemList, $id);
468: my $totalTries = 0;
469: my $totalAwarded = 0;
470: my $correct = 0;
471: my $correctByOverride = 0;
472: my $studentCount = 0;
473: my $maxTries = 0;
474: my $totalFirst = 0;
475: my @studentTries=();
476: foreach(@$students) {
477: my $code = $cache->{"$_:$problemID:$part:code"};
478:
479: if(defined($cache->{$_.':error'}) || $code eq ' ' ||
480: $cache->{"$_:$problemID:NoVersion"} eq 'true') {
481: next;
482: }
483:
484: $studentCount++;
485: my $tries = $cache->{"$_:$problemID:$part:tries"};
486: if($maxTries < $tries) {
487: $maxTries = $tries;
488: }
489: $totalTries += $tries;
490: push(@studentTries, $tries);
491:
492: my $awarded = $cache->{"$_:$problemID:$part:awarded"};
493: $totalAwarded += $awarded;
494:
495: if($code eq '*') {
496: $correct++;
497: if($tries == 1) {
498: $totalFirst++;
499: }
500: } elsif($code eq '+') {
501: $correctByOverride++;
502: }
503: }
504:
505: $problemData{$id.':sequenceTitle'} =
506: $cache->{$sequence.':title'};
507: $problemData{$id.':studentCount'} = $studentCount;
508: $problemData{$id.':totalTries'} = $totalTries;
509: $problemData{$id.':studentTries'} = \@studentTries;
510: $problemData{$id.':totalAwarded'} = $totalAwarded;
511: $problemData{$id.':correct'} = $correct;
512: $problemData{$id.':correctByOverride'} = $correctByOverride;
513: $problemData{$id.':wrong'} = $studentCount -
514: ($correct + $correctByOverride);
515: $problemData{$id.':maxTries'} = $maxTries;
516: $problemData{$id.':totalFirst'} = $totalFirst;
517: }
518: }
519: }
520:
521: $problemData{'problemList'} = \@problemList;
522: # $Discussed=0;
523: # if($Discuss->{"$name:$problem"}) {
524: # $TotDiscuss++;
525: # $Discussed=1;
526: # }
527:
528: return \%problemData;
529: }
530:
531: sub SortProblems {
532: my ($problemData,$sortBy,$ascend)=@_;
533:
534: if($sortBy eq "Homework Sets Order") {
535: return;
536: }
537:
538: my $data;
539:
540: if ($sortBy eq "#Stdnts") { $data = ':studentCount'; }
541: elsif($sortBy eq "Tries") { $data = ':totalTries'; }
542: elsif($sortBy eq "Mod") { $data = ':maxTries'; }
543: elsif($sortBy eq "Mean") { $data = ':mean'; }
544: elsif($sortBy eq "#YES") { $data = ':correct'; }
545: elsif($sortBy eq "#yes") { $data = ':correctByOverride'; }
546: elsif($sortBy eq "%Wrng") { $data = ':percentWrong'; }
547: elsif($sortBy eq "DoDiff") { $data = ':degreeOfDifficulty'; }
548: elsif($sortBy eq "S.D.") { $data = ':standardDeviation'; }
549: elsif($sortBy eq "Skew.") { $data = ':skewness'; }
550: elsif($sortBy eq "D.F.1st") { $data = ':discriminantFactor1'; }
551: elsif($sortBy eq "D.F.2nd") { $data = ':discriminantFactor2'; }
552: elsif($sortBy eq "Disc.") { $data = ''; }
553: else { return; }
554:
555: my $problems = $problemData->{'problemList'};
556: my @orderedProblems =
557: sort { $problemData->{$a.$data} <=> $problemData->{$b.$data} }
558: @$problems;
559: if($ascend eq 'Descending') {
560: @orderedProblems = reverse(@orderedProblems);
561: }
562:
563: $problemData->{'problemList'} = \@orderedProblems;
564:
565: return;
566: }
567:
568: sub CalculateStatistics {
569: my ($data)=@_;
570:
571: my $problems = $data->{'problemList'};
572: foreach(@$problems) {
573: # Mean
574: $data->{$_.':mean'} = ($data->{$_.':studentCount'}) ?
575: ($data->{$_.':totalTries'} / $data->{$_.':studentCount'}) : 0;
576:
577: # %Wrong
578: $data->{$_.':percentWrong'} = ($data->{$_.':studentCount'}) ?
579: (($data->{$_.':wrong'} / $data->{$_.':studentCount'}) * 100.0) :
580: 100.0;
581:
582: # Degree of Difficulty
583: $data->{$_.':degreeOfDifficulty'} = ($data->{$_.':totalTries'}) ?
584: (1 - (($data->{$_.':correct'} + $data->{$_.':correctByOverride'}) /
585: $data->{$_.':totalTries'})) : 0;
586:
587: # Factor in mean
588: my $studentTries = $data->{$_.':studentTries'};
589: foreach(my $index=0; $index < scalar(@$studentTries); $index++) {
590: $studentTries->[$index] -= $data->{$_.':mean'};
591: }
592: my $sumSquared = 0;
593: my $sumCubed = 0;
594: foreach(@$studentTries) {
595: my $squared = ($_ * $_);
596: my $cubed = ($squared * $_);
597: $sumSquared += $squared;
598: $sumCubed += $cubed;
599: }
600:
601: # Standard deviation
602: $data->{$_.':standardDeviation'} = ($data->{$_.':studentCount'} - 1) ?
603: ((sqrt($sumSquared)) / ($data->{$_.':studentCount'} - 1)) : 0;
604:
605: # Skewness
606: my $standardDeviation = $data->{$_.':standardDeviation'};
607: $data->{$_.':skewness'} = ($data->{$_.':standardDeviation'}) ?
608: (((sqrt($sumSquared)) / $data->{$_.':studentCount'}) /
609: ($standardDeviation * $standardDeviation * $standardDeviation)) :
610: 0;
611:
612: # Discrimination Factor 1
613: $data->{$_.':discriminationFactor1'} = 0;
614:
615: # Discrimination Factor 2
616: $data->{$_.':discriminationFactor2'} = 0;
617: }
618:
619: return;
620: }
621:
1.4 minaeibi 622: sub ProcessDiscriminant {
1.19 stredwic 623: my ($List) = @_;
1.4 minaeibi 624: my @sortedList = sort (@$List);
625: my $Count = scalar @sortedList;
626: my $Problem;
627: my @Dis;
628: my $Slvd=0;
629: my $tmp;
630: my $Sum1=0;
631: my $Sum2=0;
632: my $nIndex=0;
633: my $nStudent=0;
634: my %Proc=undef;
635: while ($nIndex<$Count) {
1.19 stredwic 636: # $jr->print("<br> $nIndex) $sortedList[$nIndex]");
1.4 minaeibi 637: ($Problem,$tmp)=split(/\=/,$sortedList[$nIndex]);
638: @Dis=split(/\+/,$tmp);
639: my $Temp = $Problem;
640: do {
641: $nIndex++;
642: $nStudent++;
643: $Sum1 += $Dis[0];
644: $Sum2 += $Dis[1];
645: ($Problem,$tmp)=split(/\=/,$sortedList[$nIndex]);
646: @Dis=split(/\+/,$tmp);
647: } while ( $Problem eq $Temp && $nIndex < $Count );
648: $Proc{$Temp}=($Sum1/$nStudent).':'.($Sum2/$nStudent);
1.19 stredwic 649: # $jr->print("<br> $nIndex) $Temp --> ($nStudent) $Proc{$Temp}");
1.4 minaeibi 650: $Sum1=0;
651: $Sum2=0;
652: $nStudent=0;
653: }
654:
655: return %Proc;
656: }
657:
658: #------- Creating Discimination factor
659: sub Discriminant {
1.19 stredwic 660: my ($discriminant)=@_;
1.7 minaeibi 661: my @discriminantKeys=keys(%$discriminant);
1.4 minaeibi 662: my $Count = scalar @discriminantKeys;
663:
664: my $UpCnt = int(0.27*$Count);
665: my $low=0;
666: my $up=$Count-$UpCnt;
667: my @UpList=();
668: my @LowList=();
669:
670: $Count=0;
671: foreach my $key (sort(@discriminantKeys)) {
672: $Count++;
673: if($low < $UpCnt || $Count > $up) {
674: $low++;
1.7 minaeibi 675: my $str=$discriminant->{$key};
676: foreach(split(/\&/,$str)){
1.4 minaeibi 677: if($_) {
678: if($low<$UpCnt) { push(@LowList,$_); }
679: else { push(@UpList,$_); }
680: }
681: }
682: }
683: }
1.19 stredwic 684: my %DisUp = &ProcessDiscriminant(\@UpList);
685: my %DisLow = &ProcessDiscriminant(\@LowList);
1.4 minaeibi 686:
687: return (\%DisUp, \%DisLow);
1.8 minaeibi 688: }
1.4 minaeibi 689:
1.1 stredwic 690: #---- END Problem Statistics Web Page ----------------------------------------
691:
692: #---- Problem Statistics Graph Web Page --------------------------------------
693:
694: # ------------------------------------------- Prepare data for Graphical chart
695:
1.16 minaeibi 696: sub BuildGraphicChart {
697: my ($ylab,$r,$cacheDB)=@_;
698: my %cache;
1.1 stredwic 699: my $Col;
700: my $data='';
701: my $count = 0;
702: my $Max = 0;
1.14 minaeibi 703:
1.18 albertel 704: unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
1.16 minaeibi 705: return '<html><body>Unable to tie database.</body></html>';
1.1 stredwic 706: }
1.16 minaeibi 707:
708: my $p_count = $cache{'ProblemCount'};
1.14 minaeibi 709:
710: for ( my $k=0; $k<$p_count;$k++) {
1.16 minaeibi 711: my @Temp=split(/\:/,$cache{'GraphGif:'.$k});
712: my $inf = $Temp[$Col];
713: if ( $Max < $inf ) {$Max = $inf;}
714: $data .= $inf.',';
715: $count++;
1.14 minaeibi 716: }
1.16 minaeibi 717: untie(%cache);
718: # $r->print("<br>count=$p_count >>data= $data");
1.14 minaeibi 719:
720: if ( $Max > 1 ) {
721: $Max += (10 - $Max % 10);
722: $Max = int($Max);
723: } else { $Max = 1; }
724:
1.16 minaeibi 725: my $cid=$ENV{'request.course.id'};
1.14 minaeibi 726:
1.16 minaeibi 727: if ( $ylab eq 'DoDiff Graph' ) {
728: $ylab = 'Degree-of-Difficulty';
729: $Col = 0;
730: } else {
731: $ylab = 'Wrong-Percentage';
732: $Col = 1;
733: }
1.14 minaeibi 734: my $Course = $ENV{'course.'.$cid.'.description'};
735: $Course =~ s/\ /"_"/eg;
1.16 minaeibi 736: my $GData=$Course.'&'.'Problems#'.'&'.$ylab.'&'.
1.14 minaeibi 737: $Max.'&'.$count.'&'.$data;
1.16 minaeibi 738:
739: $r->print('<IMG src="/cgi-bin/graph.gif?'.$GData.'" />');
740:
741: return;
1.1 stredwic 742: }
1.4 minaeibi 743:
1.1 stredwic 744: 1;
745: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>