// // MWKappa.m // TEST2 // // Created by matthew on Thu Aug 14 2003. // Copyright (c) 2003 __MyCompanyName__. All rights reserved. // #import "tams.h" #import "MWKappa.h" #import "tamsutils.h" #define COLWIDTH 90.0 @implementation MWKappa -(id) init { [super init]; fileTitles = [[NSMutableString alloc] init]; answers = [[NSMutableArray alloc] init]; return self; } -(void) dealloc { [ef release]; [fileTitles release]; [answers release]; [ myKMatrix release]; [super dealloc]; } - (NSString *)windowNibName { // Implement this to return a nib to load OR implement -makeWindowControllers to manually create your controllers. return @"kappa"; } - (NSData *)dataRepresentationOfType:(NSString *)type { // Implement to provide a persistent data representation of your document OR remove this and implement the file-wrapper or file path based save methods. NSMutableData *dd; NSNumber *e; float ee; int i, n, cnt; cnt = [hotCodeList count]; dd = [[NSMutableData alloc] init]; //print the top DATASTRING(dd, fileTitles); DATANL(dd); DATASTRING(dd, [NSString stringWithFormat: @"Cohen's kappa = %.3f; %d agreements/%d opportunities (%.3f)", kappa, agreements, totCount, ((float) agreements)/totCount]); DATANL(dd); FORALL(hotCodeList) { DATATAB(dd); DATASTRING(dd, temp); } ENDFORALL; DATATAB(dd); DATASTRING(dd,@"EF"); DATATAB(dd); DATASTRING(dd,@"Total"); DATANL(dd); //Go through the hotcode list for(i = 0; i < cnt; i++) { //print the code name DATASTRING(dd, [hotCodeList objectAtIndex: i]); //print the data FORALL(hotCodeList) { DATATAB(dd); DATASTRING(dd, [NSString stringWithFormat: @"%d", [myKMatrix intForKey1: [hotCodeList objectAtIndex: i] key2: temp]]); } ENDFORALL; e = [ef objectForKey: [hotCodeList objectAtIndex: i]]; if(e == nil) ee = 0.0; else ee = [e floatValue]; //we're on a diagonal DATATAB(dd); DATASTRING(dd, [NSString stringWithFormat: @"%.3f", ee]); DATATAB(dd); DATASTRING(dd ,[NSString stringWithFormat: @"%d", [myKMatrix sumForKey1: [hotCodeList objectAtIndex: i]]]); DATANL(dd); } DATASTRING(dd, @"Total"); FORALL(hotCodeList) { DATATAB(dd); DATASTRING(dd, [NSString stringWithFormat: @"%d", [myKMatrix sumForKey2: temp]]); } ENDFORALL; DATATAB(dd); DATASTRING(dd, [NSString stringWithFormat: @"%.3f", effAgSum]); DATATAB(dd); DATASTRING(dd, [NSString stringWithFormat: @"%d", totCount]); DATANL(dd);DATANL(dd); //summary of the results DATASTRING(dd, @"Item\tCoder 1\tCoder 2\n"); for(n = 1; n<= totCount; n++) { NSString *tmp1, *tmp2; NSMutableDictionary *temp; temp = [answers objectAtIndex: n-1]; DATASTRING(dd, [NSString stringWithFormat: @"%d\t%@\t%@\n", n, (((tmp1 = [temp objectForKey: @"alpha"]) != nil)? tmp1: @""), (((tmp2 = [temp objectForKey: @"beta"]) != nil)? tmp2: @"")]); } return dd; } - (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)type { // Implement to load a persistent data representation of your document OR remove this and implement the file-wrapper or file path based load methods. return YES; } -(void) buildKappa { NSArray *rows; NSArray *mf; int qcnt, tcnt; float effAg; ctQChar *q; //make an array of the right codes based on n #ifdef levels FORALL(hcl) { if(codeLevel(temp) <= lvl) [realCodeList addObject: [[temp copy] autorelease]]; } ENDFORALL; #endif myKMatrix = [[MWDoubleDictionary alloc] init]; ef = [[NSMutableDictionary alloc] init]; mf = [tce hotFileList]; [fileTitles setString: [NSString stringWithFormat: @"%@ x %@", [[mf objectAtIndex: 0] name], [[mf objectAtIndex: 1] name]]]; [theFileTitle setStringValue: fileTitles]; //initialize a count qcnt = 0; tcnt = 0; //a flag for which coder it is //first time through make an array theDData = [[NSMutableDictionary alloc] init]; q = [[ctQChar alloc] init]; [answers addObject: [NSMutableDictionary dictionary]]; while([tce scanNext: q] != ENDOFALLFILES) { if([q tokentype] == TOKEN) { //[theDData setObject: [NSMutableDictionary dictionary] forKey: [[[q buff] copy] autorelease]]; if(tcnt == 0) [[answers objectAtIndex: qcnt] setObject: [[[q buff] copy] autorelease] forKey: @"alpha"]; else [[answers objectAtIndex: qcnt] setObject: [[[q buff] copy] autorelease] forKey: @"beta"]; } if([q tokentype] == META) { if([[q buff] isEqualToString: @"endsection"]) { [answers addObject: [NSMutableDictionary dictionary]]; qcnt++; } if([[q buff] isEqualToString: @"end"]) { //tot = qcnt; qcnt = 0; tcnt++; } } } //then convert the dictionary: FORALL(answers) { if([temp objectForKey: @"alpha"] != nil && [temp objectForKey: @"beta"] != nil) [myKMatrix incKey1: [temp objectForKey: @"alpha"] key2: [temp objectForKey: @"beta"]]; } ENDFORALL; //for each alpha code add it to a dictionary with a dictionary as the object //for each beta make it the key of the second dictionary and an NSNumber as the count //expected frequency of agreement rowsum*colsum/tot; agreements = [myKMatrix diagSum]; rows = [myKMatrix firstKeys]; effAgSum = 0.0; totCount = 0; FORALL(rows) { totCount += [myKMatrix sumForKey1: temp]; } ENDFORALL; FORALL(rows) { int colCount; int rowCount = [myKMatrix sumForKey1: temp]; colCount = [myKMatrix sumForKey2: temp]; effAg = rowCount * colCount; effAg /= totCount; // effAg = ((float) rowCount) *colCount /((float) agreements); [ef setObject: [NSNumber numberWithFloat: effAg] forKey: temp]; effAgSum += effAg; } ENDFORALL; kappa = (agreements - effAgSum)/(float)(totCount - effAgSum); [theMessage setStringValue: [NSString stringWithFormat: @"Cohen's kappa = %.3f; %d agreements/%d opportunities (%.3f)", kappa, agreements, totCount, ((float) agreements)/totCount]]; [self setupTable]; [theTable reloadData]; [ansTable reloadData]; [self updateChangeCount: NSChangeDone]; } -(void) setupTable { NSTableColumn *t; //make it the first column t = [[NSTableColumn alloc] initWithIdentifier: @".Codes"]; [t setWidth: COLWIDTH]; [theTable addTableColumn: t]; [[t headerCell] setStringValue: @"Codes"]; //Add a column for each and FORALL(hotCodeList) { t = [[NSTableColumn alloc] initWithIdentifier: temp]; [t setWidth: COLWIDTH]; [theTable addTableColumn: t]; [[t headerCell] setStringValue: temp]; }ENDFORALL; //make it the first column t = [[NSTableColumn alloc] initWithIdentifier: @".EF"]; [t setWidth: COLWIDTH]; [theTable addTableColumn: t]; [[t headerCell] setStringValue: @"EF"]; t = [[NSTableColumn alloc] initWithIdentifier: @".RTotals"]; [t setWidth: COLWIDTH]; [theTable addTableColumn: t]; [[t headerCell] setStringValue: @"Total"]; } /* table portion */ - (int)numberOfRowsInTableView:(NSTableView *)aTableView { if(aTableView == ansTable) return totCount; return [hotCodeList count] + 1; } - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn: (NSTableColumn *)aTableColumn row:(int)rowIndex { NSNumber *e; int cnt; float ee; cnt = [hotCodeList count]; if(aTableView == ansTable) { NSLog(@"Building back table\n"); if([[aTableColumn identifier] isEqualToString: @"Item"] == YES) { //return [NSString stringWithFormat: @"%d", rowIndex+1]; NSLog(@"returning %d\n",rowIndex+1); return [NSNumber numberWithInt: rowIndex+1]; } else if([[aTableColumn identifier] isEqualToString: @"Coder 1"] == YES) { return [[answers objectAtIndex: rowIndex] objectForKey: @"alpha"]; } else if([[aTableColumn identifier] isEqualToString: @"Coder 2"] == YES) { return [[answers objectAtIndex: rowIndex] objectForKey: @"beta"]; } } if([[aTableColumn identifier] isEqualToString: @".Codes"] == YES) { if(rowIndex >= cnt) { return @"Total"; } return [hotCodeList objectAtIndex: rowIndex]; } if([[aTableColumn identifier] isEqualToString: @".RTotals"] == YES) { if(rowIndex < cnt) return [NSNumber numberWithInt: [myKMatrix sumForKey1: [hotCodeList objectAtIndex: rowIndex]]]; else return [NSNumber numberWithInt: totCount]; } if([[aTableColumn identifier] isEqualToString: @".EF"] == YES) { if(rowIndex < cnt) { e = [ef objectForKey: [hotCodeList objectAtIndex: rowIndex]]; if(e == nil) ee = 0.0; else ee = [e floatValue]; return [NSString stringWithFormat: @"%.3f", ee]; } else return [NSString stringWithFormat: @"%.3f", effAgSum]; } if(rowIndex >= cnt) { return [NSNumber numberWithInt: [myKMatrix sumForKey2: [aTableColumn identifier]]]; } return [NSString stringWithFormat: @"%d", [myKMatrix intForKey1: [hotCodeList objectAtIndex: rowIndex] key2: [aTableColumn identifier]]]; } @end