Mercurial > hg > chime-home-dataset-annotation-and-baseline-evaluation-code
view analysis_of_annotations/evaluate_annotations.py @ 5:b523456082ca tip
Update path to dataset and reflect modified chunk naming convention.
author | peterf |
---|---|
date | Mon, 01 Feb 2016 21:35:27 +0000 |
parents | f079d2de4aa2 |
children |
line wrap: on
line source
#!/usr/bin/python # # evaluate_annotations.py: # Compute descriptive statistics of annotations, including annotator # agreement # # Author: Peter Foster # (c) 2015 Peter Foster # from pandas import Series, DataFrame import glob import pandas.io.parsers from pylab import * import numpy as np import re DatasetPath = '/import/c4dm-02/people/peterf/audex/datasets/chime_home/' #Read in annotations Chunks = list(Series.from_csv(DatasetPath + 'release_chunks_raw.csv',header=None)) Annotations = [] for chunk in Chunks: Annotations.append(Series.from_csv(DatasetPath + 'chunks/' + chunk + '.csv')) Annotations = DataFrame(Annotations) Annotators = ('annotation_a1', 'annotation_a2', 'annotation_a3') #Check label integrity Labels = set('cmfvpboSU') for a in Annotators: I = Annotations[a].notnull() Annotations[a].ix[I] = Annotations[a][I].apply(lambda s: ''.join(sorted(s))) assert(all(Annotations[a].ix[I].apply(lambda s: len(set(s).difference(Labels)) == 0))) #Annotator-wise label counts CountStats = {'annotatorwise':{}, 'majorityvote':{}} for annotator in Annotators: CountStats['annotatorwise'][annotator] = {} for label in Labels: V1 = Annotations[annotator][Annotations[annotator].notnull()] V1 = V1.apply(lambda s: label in s) CountStats['annotatorwise'][annotator][label] = sum(V1) CountStats['annotatorwise'] = DataFrame(CountStats['annotatorwise']) #Rearrange index for plotting histogram CountStats['annotatorwise'] = CountStats['annotatorwise'].ix[['c','m','f','v','p','b','o','S','U']] CountStats['annotatorwise_coefficient_of_variation'] = (CountStats['annotatorwise'].T.std() / CountStats['annotatorwise'].T.mean()) CountStats['annotatorwise_coefficient_of_variation'].sort() #Histogram of label counts fig_width_pt = 246.0 # Get this from LaTeX using \showthe\columnwidth inches_per_pt = 1.0/72.27 # Convert pt to inch golden_mean = (sqrt(5)-1.0)/2.0 # Aesthetic ratio fig_width = fig_width_pt*inches_per_pt # width in inches fig_height = fig_width*golden_mean # height in inches fig_size = [fig_width,fig_height] params = {'backend': 'ps', 'axes.labelsize': 8, 'text.fontsize': 8, 'legend.fontsize': 7.0, 'xtick.labelsize': 8, 'ytick.labelsize': 8, 'text.usetex': False, 'figure.figsize': fig_size} rcParams.update(params) ind = np.arange(len(CountStats['annotatorwise'])) # the x locations for the groups width = 0.29 # the width of the bars fig, ax = plt.subplots() rects = [] colours = ('r', 'y', 'g') for annotator, i in zip(Annotators, range(len(Annotators))): rects.append(ax.bar(ind+width*i, CountStats['annotatorwise'][annotator], width, color=colours[i], align='center')) # add text for labels, title and axes ticks ax.set_ylabel('Count') ax.set_xlabel('Label') #ax.set_title('Annotator-wise label histogram') ax.set_xticks(ind+width) ax.set_xticklabels(CountStats['annotatorwise'].index) ax.legend( (rect[0] for rect in rects), ('Annotator 1', 'Annotator 2', 'Annotator 3') ) #Tweak x-axis limit ax.set_xlim(left=-0.5) ax.set_ylim(top=3500) plt.gcf().subplots_adjust(left=0.15) #Prevent y-axis label from being chopped off def autolabel(r): for rects in r: for rect in rects: height = rect.get_height() ax.text(rect.get_x()+0.180,100+height,'%d'%int(height),ha='center',va='bottom',rotation='vertical',size=6.0) autolabel(rects) plt.draw() plt.savefig('figures/annotation_histogram.pdf') #Generalised Jaccard index def jaccardIndex(*Sets): SetN = Sets[0] SetD = Sets[0] for S in Sets: SetN = SetN.intersection(S) SetD = SetD.union(S) if len(SetD) == 0: return 1 else: return len(SetN) / float(len(SetD)) AgreementStats = {'jaccardindex_pos':{}} for l in Labels: V1 = set(np.where(Annotations['annotation_a1'].apply(lambda s: l in s))[0]) V2 = set(np.where(Annotations['annotation_a2'].apply(lambda s: l in s))[0]) V3 = set(np.where(Annotations['annotation_a3'].apply(lambda s: l in s))[0]) AgreementStats['jaccardindex_pos'][l] = {} AgreementStats['jaccardindex_pos'][l]['a1_a2_a3'] = jaccardIndex(V1, V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a2'] = jaccardIndex(V1, V2) AgreementStats['jaccardindex_pos'][l]['a2_a3'] = jaccardIndex(V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a3'] = jaccardIndex(V1, V3) #Experiment with combining label classes V1 = set(np.where(Annotations['annotation_a1'].apply(lambda s: 'o' in s or 'p' in s))[0]) V2 = set(np.where(Annotations['annotation_a2'].apply(lambda s: 'o' in s or 'p' in s))[0]) V3 = set(np.where(Annotations['annotation_a3'].apply(lambda s: 'o' in s or 'p' in s))[0]) l = '{o,p}' AgreementStats['jaccardindex_pos'][l] = {} AgreementStats['jaccardindex_pos'][l]['a1_a2_a3'] = jaccardIndex(V1, V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a2'] = jaccardIndex(V1, V2) AgreementStats['jaccardindex_pos'][l]['a2_a3'] = jaccardIndex(V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a3'] = jaccardIndex(V1, V3) l = '{o,b}' V1 = set(np.where(Annotations['annotation_a1'].apply(lambda s: 'o' in s or 'b' in s))[0]) V2 = set(np.where(Annotations['annotation_a2'].apply(lambda s: 'o' in s or 'b' in s))[0]) V3 = set(np.where(Annotations['annotation_a3'].apply(lambda s: 'o' in s or 'b' in s))[0]) AgreementStats['jaccardindex_pos'][l] = {} AgreementStats['jaccardindex_pos'][l]['a1_a2_a3'] = jaccardIndex(V1, V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a2'] = jaccardIndex(V1, V2) AgreementStats['jaccardindex_pos'][l]['a2_a3'] = jaccardIndex(V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a3'] = jaccardIndex(V1, V3) l = '{o,S}' V1 = set(np.where(Annotations['annotation_a1'].apply(lambda s: 'o' in s or 'S' in s))[0]) V2 = set(np.where(Annotations['annotation_a2'].apply(lambda s: 'o' in s or 'S' in s))[0]) V3 = set(np.where(Annotations['annotation_a3'].apply(lambda s: 'o' in s or 'S' in s))[0]) AgreementStats['jaccardindex_pos'][l] = {} AgreementStats['jaccardindex_pos'][l]['a1_a2_a3'] = jaccardIndex(V1, V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a2'] = jaccardIndex(V1, V2) AgreementStats['jaccardindex_pos'][l]['a2_a3'] = jaccardIndex(V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a3'] = jaccardIndex(V1, V3) AgreementStats['jaccardindex_pos'] = DataFrame(AgreementStats['jaccardindex_pos']).T AgreementStats['jaccardindex_pos'] = AgreementStats['jaccardindex_pos'][['a1_a2', 'a1_a3', 'a2_a3', 'a1_a2_a3']] print('Agreement about label presence (unfiltered dataset)') print(AgreementStats['jaccardindex_pos'].ix[['c','m','f','v','p','b','o','S','{o,p}','{o,b}','{o,S}']]) #Coefficients of variation across pairs of annotators A = (AgreementStats['jaccardindex_pos'].ix[['c','m','f','v','p','b','o','S','{o,p}','{o,b}','{o,S}']][['a1_a2', 'a1_a3', 'a2_a3']].T) print('Coefficients of variation') print(A.std() / A.mean()) #Read in annotations for refined dataset Chunks = list(Series.from_csv(DatasetPath + 'release_chunks_refined.csv',header=None)) Annotations = [] for chunk in Chunks: Annotations.append(Series.from_csv(DatasetPath + 'chunks/' + chunk + '.csv')) Annotations = DataFrame(Annotations) AgreementStats = {'jaccardindex_pos':{}} for l in Labels: V1 = set(np.where(Annotations['annotation_a1'].apply(lambda s: l in s))[0]) V2 = set(np.where(Annotations['annotation_a2'].apply(lambda s: l in s))[0]) V3 = set(np.where(Annotations['annotation_a3'].apply(lambda s: l in s))[0]) AgreementStats['jaccardindex_pos'][l] = {} AgreementStats['jaccardindex_pos'][l]['a1_a2_a3'] = jaccardIndex(V1, V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a2'] = jaccardIndex(V1, V2) AgreementStats['jaccardindex_pos'][l]['a2_a3'] = jaccardIndex(V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a3'] = jaccardIndex(V1, V3) #Experiment with combining label classes V1 = set(np.where(Annotations['annotation_a1'].apply(lambda s: 'o' in s or 'p' in s))[0]) V2 = set(np.where(Annotations['annotation_a2'].apply(lambda s: 'o' in s or 'p' in s))[0]) V3 = set(np.where(Annotations['annotation_a3'].apply(lambda s: 'o' in s or 'p' in s))[0]) l = '{o,p}' AgreementStats['jaccardindex_pos'][l] = {} AgreementStats['jaccardindex_pos'][l]['a1_a2_a3'] = jaccardIndex(V1, V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a2'] = jaccardIndex(V1, V2) AgreementStats['jaccardindex_pos'][l]['a2_a3'] = jaccardIndex(V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a3'] = jaccardIndex(V1, V3) l = '{o,b}' V1 = set(np.where(Annotations['annotation_a1'].apply(lambda s: 'o' in s or 'b' in s))[0]) V2 = set(np.where(Annotations['annotation_a2'].apply(lambda s: 'o' in s or 'b' in s))[0]) V3 = set(np.where(Annotations['annotation_a3'].apply(lambda s: 'o' in s or 'b' in s))[0]) AgreementStats['jaccardindex_pos'][l] = {} AgreementStats['jaccardindex_pos'][l]['a1_a2_a3'] = jaccardIndex(V1, V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a2'] = jaccardIndex(V1, V2) AgreementStats['jaccardindex_pos'][l]['a2_a3'] = jaccardIndex(V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a3'] = jaccardIndex(V1, V3) l = '{o,S}' V1 = set(np.where(Annotations['annotation_a1'].apply(lambda s: 'o' in s or 'S' in s))[0]) V2 = set(np.where(Annotations['annotation_a2'].apply(lambda s: 'o' in s or 'S' in s))[0]) V3 = set(np.where(Annotations['annotation_a3'].apply(lambda s: 'o' in s or 'S' in s))[0]) AgreementStats['jaccardindex_pos'][l] = {} AgreementStats['jaccardindex_pos'][l]['a1_a2_a3'] = jaccardIndex(V1, V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a2'] = jaccardIndex(V1, V2) AgreementStats['jaccardindex_pos'][l]['a2_a3'] = jaccardIndex(V2, V3) AgreementStats['jaccardindex_pos'][l]['a1_a3'] = jaccardIndex(V1, V3) AgreementStats['jaccardindex_pos'] = DataFrame(AgreementStats['jaccardindex_pos']).T AgreementStats['jaccardindex_pos'] = AgreementStats['jaccardindex_pos'][['a1_a2', 'a1_a3', 'a2_a3', 'a1_a2_a3']] print('Agreement about label presence (refined dataset)') print(AgreementStats['jaccardindex_pos'].ix[['c','m','f','v','p','b','o','S','{o,p}','{o,b}','{o,S}']]) #Coefficients of variation across pairs of annotators A = (AgreementStats['jaccardindex_pos'].ix[['c','m','f','v','p','b','o','S','{o,p}','{o,b}','{o,S}']][['a1_a2', 'a1_a3', 'a2_a3']].T) print('Coefficients of variation') print(A.std() / A.mean()) #Label count stats for majority vote CountStats['majorityvote'] = {} for label in 'cmfvpboS': CountStats['majorityvote'][label] = {} for comparisonLabel in 'cmfvpboS': V1 = Annotations['majorityvote'] V1 = V1.apply(lambda s: label in s and comparisonLabel in s) CountStats['majorityvote'][label][comparisonLabel] = sum(V1) CountStats['majorityvote'] = DataFrame(CountStats['majorityvote']) print('Label co-occurrences') CountStats['majorityvote'].loc[['c','m','f','v','p','b','o','S'],['c','m','f','v','p','b','o','S']]