00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifndef ETIRM_START3PL_H_
00022 #define ETIRM_START3PL_H_
00023
00024 #ifdef ETIRM_NO_DIR_PREFIX
00025 #include "etirmtypes.h"
00026 #else
00027 #include "etirm/etirmtypes.h"
00028 #endif
00029
00030 #include <set>
00031 #include <cmath>
00032
00033 #ifdef BOOST_NO_STDC_NAMESPACE
00034 namespace std
00035 { using ::sqrt; using ::log; using ::fabs;}
00036 #endif
00037
00038 namespace etirm
00039 {
00040
00041 const Real invalidLogit = 10000.0;
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065 template <class RI, class II> void PersonMoments(RI iresp, II iitem, RealVector &itemdiff,
00066 Response notPresentedResponse, Real *mean, Real *variance)
00067 {
00068
00069
00070 RealVector::iterator idiff = itemdiff.begin();
00071 int total = 0;
00072 *mean = 0.0;
00073 *variance = 0.0;
00074 for (int i = itemdiff.size(); i--; ++iitem, ++idiff)
00075 {
00076 Response resp = iresp[(*iitem)->Index()];
00077 if (resp != notPresentedResponse && *idiff != invalidLogit)
00078 {
00079 *mean += *idiff;
00080 *variance += *idiff * *idiff;
00081 ++total;
00082 }
00083 }
00084
00085 *mean /= total;
00086 *variance /= total;
00087 *variance -= *mean * *mean;
00088 }
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111 template <class IE, class RI> void ItemMoments(int num_examinees, IE begin_examinee, int item,
00112 RealVector &abilities, Response notPresentedResponse, double *mean, double *variance)
00113 {
00114
00115 RealVector::iterator iabil = abilities.begin();
00116 IE ie = begin_examinee;
00117 Real total = 0;
00118 *mean = 0.0;
00119 *variance = 0.0;
00120 for (int i = num_examinees; i--; ++ie, ++iabil)
00121 {
00122 RI resp = (*ie)->responses_begin() + item;
00123 Real count = (*ie)->Count();
00124
00125 if (*resp != notPresentedResponse && *iabil != invalidLogit)
00126 {
00127 *mean += *iabil * count;
00128 *variance += *iabil * *iabil * count;
00129 total += count;
00130 }
00131 }
00132
00133 *mean /= total;
00134 *variance /= total;
00135 *variance -= *mean * *mean;
00136 }
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176 template <class EI, class RI, class II> void PROX(int numItems, bool useAll, EI begin_examinee,
00177 EI end_examinee, II begin_item, Response notPresentedResponse, RealVector &itemdiff,
00178 RealVector &abilities)
00179 {
00180 const int maxIter = 10;
00181 const double convergenceCrit = 0.01;
00182
00183 int i, iitem;
00184 int num_examinees = end_examinee - begin_examinee;
00185 RealVector logitDiff(numItems);
00186 RealVector logitAbility(num_examinees);
00187
00188
00189 RealVector::iterator ilogit = logitDiff.begin();
00190 for (i=0; i<numItems; ++i, ++ilogit)
00191 {
00192 Real total = 0.0;
00193 Real sum = 0.0;
00194 EI ie = begin_examinee;
00195 int nvalid = 0;
00196 iitem = begin_item[i]->Index();
00197 Response correct = begin_item[i]->CorrectResponse();
00198 while (ie != end_examinee)
00199 {
00200 RI ir = (*ie)->responses_begin() + iitem;
00201 if (*ir != notPresentedResponse)
00202 {
00203 if (*ir == correct)
00204 sum += (*ie)->Count();
00205 total += (*ie)->Count();
00206 ++nvalid;
00207 }
00208 ++ie;
00209 }
00210
00211 if (total == 0.0)
00212 throw RuntimeError("No valid responses for an item", "PROX");
00213
00214 if (sum == 0.0 || sum == total)
00215 {
00216 if (useAll)
00217 {
00218 Real halfCount = total / (2*nvalid);
00219 Real maxLogit = std::log(halfCount / (total-halfCount));
00220
00221
00222 *ilogit = (sum == 0.0) ? maxLogit : (1.0 / maxLogit);
00223 }
00224 else
00225 {
00226 *ilogit = invalidLogit;
00227 }
00228 }
00229 else
00230 {
00231 *ilogit = std::log(sum / (total-sum));
00232 }
00233 }
00234
00235
00236 ilogit = logitAbility.begin();
00237 for (EI ie = begin_examinee; ie != end_examinee; ++ie, ++ilogit)
00238 {
00239 Real total = 0.0;
00240 Real sum = 0.0;
00241 II item = begin_item;
00242 RI bresp = (*ie)->responses_begin();
00243 for (i=numItems; i--; ++item)
00244 {
00245 Response resp = bresp[(*item)->Index()];
00246 if (resp != notPresentedResponse)
00247 {
00248 if (resp == (*item)->CorrectResponse())
00249 ++sum;
00250 ++total;
00251 }
00252 }
00253
00254 if (total == 0.0)
00255 {
00256 *ilogit = invalidLogit;
00257 }
00258 else if (sum == 0.0 || sum == total)
00259 {
00260 if (useAll)
00261 {
00262
00263 *ilogit = (sum == 0.0) ? (std::log(0.5 / (total-0.5))) : std::log((total - 0.5) / 0.5);
00264 }
00265 else
00266 {
00267 *ilogit = invalidLogit;
00268 }
00269 }
00270 else
00271 {
00272 *ilogit = std::log(sum / (total-sum));
00273 }
00274 }
00275
00276 int iter;
00277 double mean = 0.0;
00278 double variance = 1.0;
00279 RealVector prevAbility(abilities);
00280 for (iter=0; iter<maxIter; ++iter)
00281 {
00282
00283 RealVector::iterator idiff = itemdiff.begin();
00284 ilogit = logitDiff.begin();
00285 Real sum = 0.0;
00286 int nvalid = 0;
00287 for (i=0; i<numItems; ++i, ++ilogit, ++idiff)
00288 {
00289 if (*ilogit != invalidLogit)
00290 {
00291
00292 if (iter > 0)
00293 {
00294 iitem = begin_item[i]->Index();
00295 ItemMoments<EI, RI>(num_examinees, begin_examinee, iitem, abilities,
00296 notPresentedResponse, &mean, &variance);
00297 }
00298
00299
00300 *idiff = mean - std::sqrt(1 + variance/2.9) * *ilogit;
00301 sum += *idiff;
00302
00303 ++nvalid;
00304 }
00305 }
00306
00307
00308 sum /= nvalid;
00309 idiff = itemdiff.begin();
00310 for (i = numItems; i--; ++idiff)
00311 {
00312 if (*idiff != invalidLogit)
00313 *idiff -= sum;
00314 }
00315
00316
00317 RealVector::iterator iabil = abilities.begin();
00318 ilogit = logitAbility.begin();
00319 for (EI ie = begin_examinee; ie != end_examinee; ++ie, ++iabil, ++ilogit)
00320 {
00321 if (*ilogit != invalidLogit)
00322 {
00323
00324 PersonMoments<RI, II>((*ie)->responses_begin(), begin_item, itemdiff, notPresentedResponse, &mean, &variance);
00325
00326
00327 *iabil = mean + std::sqrt(1 + variance/2.9) * *ilogit;
00328 }
00329 }
00330
00331
00332 if (iter > 0)
00333 {
00334 Real maxdiff = 0.0;
00335 for (i=0; i<num_examinees; ++i)
00336 {
00337 if (abilities[i] != invalidLogit)
00338 {
00339 Real diff = std::fabs(abilities[i] - prevAbility[i]);
00340 if (diff > maxdiff)
00341 maxdiff = diff;
00342 }
00343 }
00344 if (maxdiff < convergenceCrit)
00345 break;
00346 }
00347 prevAbility = abilities;
00348 }
00349 }
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376 template <class I> void AssignItemNR(int n, RealVector::iterator itemTheta,
00377 RealVector::iterator nVec, RealVector::iterator rVec, I *item)
00378 {
00379 int i;
00380
00381 int ncat = item->NumLatentVarCat();
00382
00383 if (ncat == 0)
00384 throw RuntimeError("Values of discrete latent variable categories are missing for an item",
00385 "AssignItemNR");
00386
00387
00388 RealVector cutpoints(ncat-1);
00389 RealVector::iterator ic = cutpoints.begin();
00390 typename I::point_iterator ip = item->GetLatentVarPoints(1);
00391 for (i=ncat-1; i--; ++ic, ++ip)
00392 {
00393 *ic = (ip[0] + ip[1]) / 2.0;
00394 }
00395
00396 item->InitializeNR();
00397 typename I::n_iterator in = item->NVector();
00398 typename I::r_iterator ir = item->RVector(item->CorrectResponse());
00399 for (; n--; ++itemTheta, ++nVec, ++rVec)
00400 {
00401
00402 ic = cutpoints.begin();
00403 for (i=0; i<ncat-1; ++i, ++ic)
00404 {
00405 if (*itemTheta < *ic)
00406 break;
00407 }
00408
00409 in[i] += *nVec;
00410 ir[i] += *rVec;
00411 }
00412 }
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467 template <class RI, class MI, class EI, class I, class II> int StartingValues3PL(MI begin_min,
00468 EI begin_examinee, EI end_examinee, II begin_item, II end_item,
00469 Response notPresentedResponse, bool useAll = false, int baseGroup = 1,
00470 std::set<I *> *calc_items = 0)
00471 {
00472
00473 int numExaminees = end_examinee - begin_examinee;
00474 int numItems = end_item - begin_item;
00475
00476 RealVector thetas(numExaminees, invalidLogit);
00477 RealVector itemDiff(numItems, invalidLogit);
00478
00479 typedef std::vector<Response> cvector;
00480
00481
00482 PROX<EI, RI, II>(numItems, useAll, begin_examinee, end_examinee, begin_item,
00483 notPresentedResponse, itemDiff, thetas);
00484
00485
00486 int i;
00487 RealVector nVec(numExaminees);
00488 RealVector::iterator in = nVec.begin();
00489 RealVector::iterator itheta = thetas.begin();
00490 Real mean = 0.0;
00491 Real nwt = 0.0;
00492 EI ie = begin_examinee;
00493 for (i = numExaminees; i--; ++in, ++itheta, ++ie)
00494 {
00495 *in = (*ie)->Count();
00496 if ((*ie)->Group() == baseGroup && *itheta != invalidLogit)
00497 {
00498 mean += *itheta * *in;
00499 nwt += *in;
00500 }
00501 }
00502 if (nwt == 0)
00503 throw RuntimeError("No examinees with valid item responses in base group",
00504 "StartingValues3PL");
00505
00506 mean /= nwt;
00507
00508
00509 Real sd = 0.0;
00510 itheta = thetas.begin();
00511 in = nVec.begin();
00512 ie = begin_examinee;
00513 for (i = numExaminees; i--; ++in, ++itheta, ++ie)
00514 {
00515 if ((*ie)->Group() == baseGroup && *itheta != invalidLogit)
00516 {
00517 Real diff = *itheta - mean;
00518 sd += diff * diff * *in;
00519 }
00520 }
00521 sd /= nwt;
00522 sd = std::sqrt(sd);
00523
00524
00525 itheta = thetas.begin();
00526 for (i=numExaminees; i--; ++itheta)
00527 {
00528 if (*itheta != invalidLogit)
00529 {
00530 *itheta -= mean;
00531 *itheta /= sd;
00532 }
00533 }
00534
00535
00536 RealVector::iterator idiff = itemDiff.begin();
00537 for (i = numItems; i--; ++idiff)
00538 {
00539 if (*idiff != invalidLogit)
00540 {
00541 *idiff -= mean;
00542 *idiff /= sd;
00543 }
00544 }
00545
00546 RealVector itemTheta(numExaminees);
00547 RealVector rVec(numExaminees);
00548
00549
00550
00551
00552 int minError = 0;
00553 for (int item = 0; item < numItems; ++item, ++begin_item)
00554 {
00555 if (calc_items)
00556 {
00557 if (calc_items->find(*begin_item) == calc_items->end())
00558 continue;
00559 }
00560
00561
00562 EI ie = begin_examinee;
00563 RealVector::iterator it = itemTheta.begin();
00564 in = nVec.begin();
00565 RealVector::iterator ir = rVec.begin();
00566 RealVector::iterator alltheta = thetas.begin();
00567 int n = 0;
00568 nwt = 0.0;
00569 Real pvalue = 0.0;
00570 Response correct = (*begin_item)->CorrectResponse();
00571 while (ie != end_examinee)
00572 {
00573 RI iresp = (*ie)->responses_begin() + (*begin_item)->Index();
00574 if (*iresp != notPresentedResponse && *alltheta != invalidLogit)
00575 {
00576 *it = *alltheta;
00577 *in = (*ie)->Count();
00578 nwt += *in;
00579 if (*iresp == correct)
00580 {
00581 pvalue += *in;
00582 *ir = *in;
00583 }
00584 else
00585 {
00586 *ir = 0.0;
00587 }
00588 ++n;
00589 ++it;
00590 ++in;
00591 ++ir;
00592 }
00593 ++alltheta;
00594
00595 ++ie;
00596 }
00597 pvalue /= nwt;
00598
00599
00600 int numParameters = (*begin_item)->NumParameters();
00601 RealVector start(numParameters);
00602 Real startb = itemDiff[item];
00603
00604 if (numParameters > 1)
00605 {
00606
00607
00608 start(1) = 1.0 / (*begin_item)->NormalizingConstant();
00609 start(2) = startb;
00610 }
00611 else
00612 {
00613 start(1) = startb;
00614 }
00615
00616
00617
00618 if (numParameters > 2)
00619 start(3) = 0.05;
00620
00621 if (pvalue == 1.0 || pvalue == 0.0)
00622 {
00623 if (!useAll)
00624 {
00625
00626
00627
00628 Real maxlogit = std::log((numExaminees - 0.5) / 0.5);
00629 startb = (pvalue == 1.0) ? maxlogit : 1.0/maxlogit;
00630 if (numParameters > 1)
00631 start(2) = startb;
00632 else
00633 start(1) = startb;
00634 }
00635 (*begin_item)->NonZeroPriors(start);
00636 (*begin_item)->SetParameters(start);
00637 }
00638 else
00639 {
00640
00641
00642
00643 AssignItemNR<I>(n, itemTheta.begin(), nVec.begin(), rVec.begin(), *begin_item);
00644
00645 (*begin_min)->SetFunction(*begin_item);
00646
00647 RealVector xpls(numParameters), gpls(numParameters);
00648 double fpls;
00649
00650
00651 (*begin_item)->NonZeroPriors(start);
00652
00653 int result = (*begin_min)->Minimize(start, xpls, fpls, gpls);
00654
00655
00656
00657
00658 if (!result || (*begin_min)->GetMessage() == 4)
00659 {
00660 (*begin_item)->SetParameters(xpls);
00661 }
00662 else
00663 {
00664 start(1) = 1.0;
00665 start(3) = 0.1;
00666 (*begin_item)->SetParameters(start);
00667 minError++;
00668 }
00669 }
00670 ++begin_min;
00671 }
00672 return minError;
00673 }
00674
00675 #endif // ETIRM_START3PL_H_
00676 }