GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 07325f...a2486a )
by Oana
19:35
created

Metrics.annotation_quality_score()   C

Complexity

Conditions 11

Size

Total Lines 70
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 11

Importance

Changes 0
Metric Value
eloc 34
dl 0
loc 70
ccs 29
cts 29
cp 1
rs 5.4
c 0
b 0
f 0
cc 11
nop 4
crap 11

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like crowdtruth.models.metrics.Metrics.annotation_quality_score() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""
2
Initialization of CrowdTruth metrics
3
"""
4 1
import logging
5 1
import math
6
7 1
from collections import Counter
8
9 1
import numpy as np
10 1
import pandas as pd
11
12 1
SMALL_NUMBER_CONST = 0.00000001
13
14 1
class Metrics():
15
    """
16
    Computes and applies the CrowdTruth metrics for evaluating units, workers and annotations.
17
    """
18
19
    # Unit Quality Score
20 1
    @staticmethod
21
    def unit_quality_score(unit_id, unit_work_ann_dict, wqs, aqs):
22
        """
23
        Computes the unit quality score.
24
25
        The unit quality score (UQS) is computed as the average cosine similarity between
26
        all worker vectors for a given unit, weighted by the worker quality (WQS) and the
27
        annotation quality (AQS). The goal is to capture the degree of agreement in annotating
28
        the media unit.
29
30
        Through the weighted average, workers and annotations with lower quality will have
31
        less of an impact on the final score.
32
33
        To weigh the metrics with the annotation quality, we compute weighted_cosine, the weighted
34
        version of the cosine similarity.
35
36
        Args:
37
            unit_id: Unit id.
38
            unit_work_ann_dict: A dictionary that contains all the workers judgments for the unit.
39
            aqs: Dict of annotation_id (string) that contains the annotation quality score (float)
40
            wqs: Dict of worker_id (string) that contains the worker quality score (float)
41
42
        Returns:
43
            The quality score (UQS) of the given unit.
44
        """
45
46 1
        uqs_numerator = 0.0
47 1
        uqs_denominator = 0.0
48 1
        worker_ids = list(unit_work_ann_dict[unit_id].keys())
49
50 1
        for worker_i in range(len(worker_ids) - 1):
51 1
            for worker_j in range(worker_i + 1, len(worker_ids)):
52
                # print worker_ids[i] + " - " + worker_ids[j] + "\n"
53 1
                numerator = 0.0
54 1
                denominator_i = 0.0
55 1
                denominator_j = 0.0
56
57 1
                worker_i_vector = unit_work_ann_dict[unit_id][worker_ids[worker_i]]
58 1
                worker_j_vector = unit_work_ann_dict[unit_id][worker_ids[worker_j]]
59
60 1
                for ann in worker_i_vector:
61 1
                    worker_i_vector_ann = worker_i_vector[ann]
62 1
                    worker_j_vector_ann = worker_j_vector[ann]
63 1
                    numerator += aqs[ann] * (worker_i_vector_ann * worker_j_vector_ann)
64 1
                    denominator_i += aqs[ann] * (worker_i_vector_ann * worker_i_vector_ann)
65 1
                    denominator_j += aqs[ann] * (worker_j_vector_ann * worker_j_vector_ann)
66
67 1
                weighted_cosine = numerator / math.sqrt(denominator_i * denominator_j)
68
69 1
                uqs_numerator += weighted_cosine * wqs[worker_ids[worker_i]] * \
70
                                 wqs[worker_ids[worker_j]]
71 1
                uqs_denominator += wqs[worker_ids[worker_i]] * wqs[worker_ids[worker_j]]
72
73 1
        if uqs_denominator < SMALL_NUMBER_CONST:
74 1
            uqs_denominator = SMALL_NUMBER_CONST
75 1
        return uqs_numerator / uqs_denominator
76
77
78
    # Worker - Unit Agreement
79 1
    @staticmethod
80
    def worker_unit_agreement(worker_id, unit_ann_dict, work_unit_ann_dict, uqs, aqs, wqs):
81
        """
82
        Computes the worker agreement on a unit.
83
84
        The worker unit agreement (WUA) is the average cosine distance between the annotations
85
        of a worker i and all the other annotations for the units they have worked on,
86
        weighted by the unit and annotation quality. It calculates how much a worker disagrees
87
        with the crowd on a unit basis.
88
89
        Through the weighted average, units and anntation with lower quality will have less
90
        of an impact on the final score.
91
92
        Args:
93
            worker_id: Worker id.
94
            unit_ann_dict: Dictionary of units and their aggregated annotations.
95
            work_unit_ann_dict: Dictionary of units (and its annotation) annotated by the worker.
96
            uqs: Dict unit_id that contains the unit quality scores (float).
97
            aqs: Dict of annotation_id (string) that contains the annotation quality scores (float).
98
            wqs: Dict of worker_id (string) that contains the worker quality scores (float).
99
100
        Returns:
101
            The worker unit agreement score for the given worker.
102
        """
103
104 1
        wsa_numerator = 0.0
105 1
        wsa_denominator = 0.0
106 1
        work_unit_ann_dict_worker_id = work_unit_ann_dict[worker_id]
107
108 1
        for unit_id in work_unit_ann_dict_worker_id:
109 1
            numerator = 0.0
110 1
            denominator_w = 0.0
111 1
            denominator_s = 0.0
112
113 1
            worker_vector = work_unit_ann_dict[worker_id][unit_id]
114 1
            unit_vector = unit_ann_dict[unit_id]
115
116 1
            for ann in worker_vector:
117 1
                worker_vector_ann = worker_vector[ann] * wqs
118 1
                unit_vector_ann = unit_vector[ann]
119
120 1
                numerator += aqs[ann] * worker_vector_ann * \
121
                    (unit_vector_ann - worker_vector_ann)
122 1
                denominator_w += aqs[ann] * \
123
                    (worker_vector_ann * worker_vector_ann)
124 1
                denominator_s += aqs[ann] * ( \
125
                    (unit_vector_ann - worker_vector_ann) * \
126
                    (unit_vector_ann - worker_vector_ann))
127 1
            weighted_cosine = None
128 1
            if math.sqrt(denominator_w * denominator_s) < SMALL_NUMBER_CONST:
129 1
                weighted_cosine = SMALL_NUMBER_CONST
130
            else:
131 1
                weighted_cosine = numerator / math.sqrt(denominator_w * denominator_s)
132 1
            wsa_numerator += weighted_cosine * uqs[unit_id]
133 1
            wsa_denominator += uqs[unit_id]
134 1
        if wsa_denominator < SMALL_NUMBER_CONST:
135 1
            wsa_denominator = SMALL_NUMBER_CONST
136 1
        return wsa_numerator / wsa_denominator
137
138
    # Worker - Worker Agreement
139 1
    @staticmethod
140
    def worker_worker_agreement(worker_id, work_unit_ann_dict, unit_work_ann_dict, wqs, uqs, aqs):
141
        """
142
        Computes the agreement between every two workers.
143
144
        The worker-worker agreement (WWA) is the average cosine distance between the annotations of
145
        a worker i and all other workers that have worked on the same media units as worker i,
146
        weighted by the worker and annotation qualities.
147
148
        The metric gives an indication as to whether there are consisently like-minded workers.
149
        This is useful for identifying communities of thought.
150
151
        Through the weighted average, workers and annotations with lower quality will have less
152
        of an impact on the final score of the given worker.
153
154
        Args:
155
            worker_id: Worker id.
156
            work_unit_ann_dict: Dictionary of worker annotation vectors on annotated units.
157
            unit_work_ann_dict: Dictionary of unit annotation vectors.
158
            uqs: Dict unit_id that contains the unit quality scores (float).
159
            aqs: Dict of annotation_id (string) that contains the annotation quality scores (float).
160
            wqs: Dict of worker_id (string) that contains the worker quality scores (float).
161
162
        Returns:
163
            The worker worker agreement score for the given worker.
164
        """
165
166 1
        wwa_numerator = 0.0
167 1
        wwa_denominator = 0.0
168
169 1
        worker_vector = work_unit_ann_dict[worker_id]
170 1
        unit_ids = list(work_unit_ann_dict[worker_id].keys())
171
172 1
        for unit_id in unit_ids:
173 1
            wv_unit_id = worker_vector[unit_id]
174 1
            unit_work_ann_dict_unit_id = unit_work_ann_dict[unit_id]
175 1
            for other_workid in unit_work_ann_dict_unit_id:
176 1
                if worker_id != other_workid:
177 1
                    numerator = 0.0
178 1
                    denominator_w = 0.0
179 1
                    denominator_ow = 0.0
180
181 1
                    unit_work_ann_dict_uid_oworkid = unit_work_ann_dict_unit_id[other_workid]
182 1
                    for ann in wv_unit_id:
183 1
                        unit_work_ann_dict_uid_oworkid_ann = unit_work_ann_dict_uid_oworkid[ann]
184 1
                        wv_unit_id_ann = wv_unit_id[ann]
185
186 1
                        numerator += aqs[ann] * (wv_unit_id_ann * \
187
                                     unit_work_ann_dict_uid_oworkid_ann)
188
189 1
                        denominator_w += aqs[ann] * (wv_unit_id_ann * wv_unit_id_ann)
190
191 1
                        denominator_ow += aqs[ann] * \
192
                                         (unit_work_ann_dict_uid_oworkid_ann *\
193
                                          unit_work_ann_dict_uid_oworkid_ann)
194
195 1
                    weighted_cosine = numerator / math.sqrt(denominator_w * denominator_ow)
196
                    # pdb.set_trace()
197 1
                    wwa_numerator += weighted_cosine * wqs[other_workid] * uqs[unit_id]
198 1
                    wwa_denominator += wqs[other_workid] * uqs[unit_id]
199 1
        if wwa_denominator < SMALL_NUMBER_CONST:
200 1
            wwa_denominator = SMALL_NUMBER_CONST
201 1
        return wwa_numerator / wwa_denominator
202
203
204
205
    # Unit - Annotation Score (UAS)
206 1
    @staticmethod
207
    def unit_annotation_score(unit_id, annotation, unit_work_annotation_dict, wqs):
208
        """
209
        Computes the unit annotation score.
210
211
        The unit - annotation score (UAS) calculates the likelihood that annotation a
212
        is expressed in unit u. It is the ratio of the number of workers that picked
213
        annotation a over all workers that annotated the unit, weighted by the worker quality.
214
215
        Args:
216
            unit_id: Unit id.
217
            annotation: Annotation.
218
            unit_work_annotation_dict: Dictionary of unit annotation vectors.
219
            wqs: Dict of worker_id (string) that contains the worker quality scores (float).
220
221
        Returns:
222
            The unit annotation score for the given unit and annotation.
223
        """
224
225 1
        uas_numerator = 0.0
226 1
        uas_denominator = 0.0
227
228 1
        worker_ids = unit_work_annotation_dict[unit_id]
229 1
        for worker_id in worker_ids:
230 1
            uas_numerator += worker_ids[worker_id][annotation] * wqs[worker_id]
231 1
            uas_denominator += wqs[worker_id]
232 1
        if uas_denominator < SMALL_NUMBER_CONST:
233 1
            uas_denominator = SMALL_NUMBER_CONST
234 1
        return uas_numerator / uas_denominator
235
236 1
    @staticmethod
237
    def compute_ann_quality_factors(numerator, denominator, work_unit_ann_dict_worker_i, \
238
                                    work_unit_ann_dict_worker_j, ann, uqs):
239
        """
240
        Computes the factors for each unit annotation.
241
        """
242 1
        for unit_id, work_unit_ann_dict_worker_i_unit in work_unit_ann_dict_worker_i.items():
243 1
            if unit_id in work_unit_ann_dict_worker_j:
244 1
                work_unit_ann_dict_worker_j_unit = work_unit_ann_dict_worker_j[unit_id]
245
246 1
                work_unit_ann_dict_worker_j_unit_ann = work_unit_ann_dict_worker_j_unit[ann]
247
248 1
                def compute_numerator_aqs(unit_id_ann_value, worker_i_ann_value, \
249
                                                          worker_j_ann_value):
250
                    """ compute numerator """
251 1
                    numerator = unit_id_ann_value * worker_i_ann_value * \
252
                                                worker_j_ann_value
253 1
                    return numerator
254
255 1
                def compute_denominator_aqs(unit_id_ann_value, worker_j_ann_value):
256
                    """ compute denominator """
257 1
                    denominator = unit_id_ann_value * worker_j_ann_value
258 1
                    return denominator
259
260 1
                numerator += compute_numerator_aqs(uqs[unit_id], \
261
                                                    work_unit_ann_dict_worker_i_unit[ann], \
262
                                                    work_unit_ann_dict_worker_j_unit_ann)
263 1
                denominator += compute_denominator_aqs(uqs[unit_id], \
264
                                                        work_unit_ann_dict_worker_j_unit_ann)
265 1
        return numerator, denominator
266
267
    # Annotation Quality Score (AQS)
268 1
    @staticmethod
269
    def annotation_quality_score(annotations, work_unit_ann_dict, uqs, wqs):
270
        """
271
        Computes the annotation quality score.
272
273
        The annotation quality score AQS calculates the agreement of selecting an annotation a,
274
        over all the units it appears in. Therefore, it is only applicable to closed tasks, where
275
        the same annotation set is used for all units. It is based on the probability that if a
276
        worker j annotates annotation a in a unit, worker i will also annotate it.
277
278
        The annotation quality score is the weighted average of these probabilities for all possible
279
        pairs of workers. Through the weighted average, units and workers with lower quality will
280
        have less of an impact on the final score of the annotation.
281
282
        Args:
283
            annotations: Possible annotations.
284
            work_unit_annotation_dict: Dictionary of worker annotation vectors on annotated units.
285
            uqs: Dict unit_id that contains the unit quality scores (float).
286
            wqs: Dict of worker_id (string) that contains the worker quality scores (float).
287
288
        Returns:
289
            The worker worker agreement score for the given worker.
290
        """
291
292 1
        aqs_numerator = dict()
293 1
        aqs_denominator = dict()
294
295 1
        for ann in annotations:
296 1
            aqs_numerator[ann] = 0.0
297 1
            aqs_denominator[ann] = 0.0
298
299 1
        for worker_i, work_unit_ann_dict_worker_i in work_unit_ann_dict.items():
300
            #work_unit_ann_dict_worker_i = work_unit_ann_dict[worker_i]
301 1
            work_unit_ann_dict_i_keys = list(work_unit_ann_dict_worker_i.keys())
302 1
            for worker_j, work_unit_ann_dict_worker_j in work_unit_ann_dict.items():
303
                #work_unit_ann_dict_worker_j = work_unit_ann_dict[worker_j]
304 1
                work_unit_ann_dict_j_keys = list(work_unit_ann_dict_worker_j.keys())
305
306 1
                length_keys = len(np.intersect1d(np.array(work_unit_ann_dict_i_keys), \
307
                                                 np.array(work_unit_ann_dict_j_keys)))
308
309 1
                if worker_i != worker_j and length_keys > 0:
310 1
                    for ann in annotations:
311 1
                        numerator = 0.0
312 1
                        denominator = 0.0
313
314 1
                        numerator, denominator = Metrics.compute_ann_quality_factors(numerator, \
315
                                                    denominator, work_unit_ann_dict_worker_i, \
316
                                                    work_unit_ann_dict_worker_j, ann, uqs)
317
318 1
                        if denominator > 0:
319 1
                            aqs_numerator[ann] += wqs[worker_i] * wqs[worker_j] * \
320
                                                        numerator / denominator
321 1
                            aqs_denominator[ann] += wqs[worker_i] * wqs[worker_j]
322
323 1
        def aqs_dict(annotations, aqs_numerator, aqs_denominator):
324
            """ create the dictionary of aqs values """
325 1
            aqs = dict()
326 1
            for ann in annotations:
327 1
                if aqs_denominator[ann] > SMALL_NUMBER_CONST:
328 1
                    aqs[ann] = aqs_numerator[ann] / aqs_denominator[ann]
329
330
                    # prevent division by zero by storing very small value instead
331 1
                    if aqs[ann] < SMALL_NUMBER_CONST:
332 1
                        aqs[ann] = SMALL_NUMBER_CONST
333
                else:
334 1
                    aqs[ann] = SMALL_NUMBER_CONST
335 1
            return aqs
336
337 1
        return aqs_dict(annotations, aqs_numerator, aqs_denominator)
338
339
340 1
    @staticmethod
341 1
    def run(results, config, max_delta=0.001):
342
        '''
343
        iteratively run the CrowdTruth metrics
344
        '''
345
346 1
        judgments = results['judgments'].copy()
347 1
        units = results['units'].copy()
348
349
        # unit_work_ann_dict, work_unit_ann_dict, unit_ann_dict
350
        # to be done: change to use all vectors in one unit
351 1
        col = list(config.output.values())[0]
352 1
        unit_ann_dict = dict(units.copy()[col])
353
354 1
        def expanded_vector(worker, unit):
355
            '''
356
            expand the vector of a worker on a given unit
357
            '''
358 1
            vector = Counter()
359 1
            for ann in unit:
360 1
                if ann in worker:
361 1
                    vector[ann] = worker[ann]
362
                else:
363 1
                    vector[ann] = 0
364 1
            return vector
365
366
        # fill judgment vectors with unit keys
367 1
        for index, row in judgments.iterrows():
368 1
            judgments.at[index, col] = expanded_vector(row[col], units.at[row['unit'], col])
369
370 1
        unit_work_ann_dict = judgments[['unit', 'worker', col]].copy().groupby('unit')
371 1
        unit_work_ann_dict = {name : group.set_index('worker')[col].to_dict() \
372
                                for name, group in unit_work_ann_dict}
373
374 1
        work_unit_ann_dict = judgments[['worker', 'unit', col]].copy().groupby('worker')
375 1
        work_unit_ann_dict = {name : group.set_index('unit')[col].to_dict() \
376
                                for name, group in work_unit_ann_dict}
377
378
        #initialize data structures
379 1
        uqs_list = list()
380 1
        wqs_list = list()
381 1
        wwa_list = list()
382 1
        wsa_list = list()
383 1
        aqs_list = list()
384
385 1
        uqs = dict((unit_id, 1.0) for unit_id in unit_work_ann_dict)
386 1
        wqs = dict((worker_id, 1.0) for worker_id in work_unit_ann_dict)
387 1
        wwa = dict((worker_id, 1.0) for worker_id in work_unit_ann_dict)
388 1
        wsa = dict((worker_id, 1.0) for worker_id in work_unit_ann_dict)
389
390 1
        uqs_list.append(uqs.copy())
391 1
        wqs_list.append(wqs.copy())
392 1
        wwa_list.append(wwa.copy())
393 1
        wsa_list.append(wsa.copy())
394
395 1
        def init_aqs(config, unit_ann_dict):
396
            """ initialize aqs depending on whether or not it is an open ended task """
397 1
            aqs = dict()
398 1
            if not config.open_ended_task:
399 1
                aqs_keys = list(unit_ann_dict[list(unit_ann_dict.keys())[0]].keys())
400 1
                for ann in aqs_keys:
401 1
                    aqs[ann] = 1.0
402
            else:
403 1
                for unit_id in unit_ann_dict:
404 1
                    for ann in unit_ann_dict[unit_id]:
405 1
                        aqs[ann] = 1.0
406 1
            return aqs
407
408 1
        aqs = init_aqs(config, unit_ann_dict)
409 1
        aqs_list.append(aqs.copy())
410
411 1
        uqs_len = len(list(uqs.keys())) * 1.0
412 1
        wqs_len = len(list(wqs.keys())) * 1.0
413 1
        aqs_len = len(list(aqs.keys())) * 1.0
414
415
        # compute metrics until stable values
416 1
        iterations = 0
417 1
        while max_delta >= 0.001:
418 1
            uqs_new = dict()
419 1
            wqs_new = dict()
420 1
            wwa_new = dict()
421 1
            wsa_new = dict()
422
423 1
            avg_uqs_delta = 0.0
424 1
            avg_wqs_delta = 0.0
425 1
            avg_aqs_delta = 0.0
426 1
            max_delta = 0.0
427
428
            # pdb.set_trace()
429
430 1
            def compute_wqs(wwa_new, wsa_new, wqs_new, work_unit_ann_dict, unit_ann_dict, \
431
                            unit_work_ann_dict, wqs_list, uqs_list, aqs_list, wqs_len, \
432
                            max_delta, avg_wqs_delta):
433
                """ compute worker quality score (WQS) """
434 1
                for worker_id, _ in work_unit_ann_dict.items():
435 1
                    wwa_new[worker_id] = Metrics.worker_worker_agreement( \
436
                             worker_id, work_unit_ann_dict, \
437
                             unit_work_ann_dict, \
438
                             wqs_list[len(wqs_list) - 1], \
439
                             uqs_list[len(uqs_list) - 1], \
440
                             aqs_list[len(aqs_list) - 1])
441 1
                    wsa_new[worker_id] = Metrics.worker_unit_agreement( \
442
                             worker_id, \
443
                             unit_ann_dict, \
444
                             work_unit_ann_dict, \
445
                             uqs_list[len(uqs_list) - 1], \
446
                             aqs_list[len(aqs_list) - 1], \
447
                             wqs_list[len(aqs_list) - 1][worker_id])
448 1
                    wqs_new[worker_id] = wwa_new[worker_id] * wsa_new[worker_id]
449 1
                    max_delta = max(max_delta, \
450
                                abs(wqs_new[worker_id] - wqs_list[len(wqs_list) - 1][worker_id]))
451 1
                    avg_wqs_delta += abs(wqs_new[worker_id] - \
452
                                         wqs_list[len(wqs_list) - 1][worker_id])
453 1
                avg_wqs_delta /= wqs_len
454
455 1
                return wwa_new, wsa_new, wqs_new, max_delta, avg_wqs_delta
456
457 1
            def reconstruct_unit_ann_dict(unit_ann_dict, work_unit_ann_dict, wqs_new):
458
                """ reconstruct unit_ann_dict with worker scores """
459 1
                new_unit_ann_dict = dict()
460 1
                for unit_id, ann_dict in unit_ann_dict.items():
461 1
                    new_unit_ann_dict[unit_id] = dict()
462 1
                    for ann, _ in ann_dict.items():
463 1
                        new_unit_ann_dict[unit_id][ann] = 0.0
464 1
                for work_id, srd in work_unit_ann_dict.items():
465 1
                    wqs_work_id = wqs_new[work_id]
466 1
                    for unit_id, ann_dict in srd.items():
467 1
                        for ann, score in ann_dict.items():
468 1
                            new_unit_ann_dict[unit_id][ann] += score * wqs_work_id
469
470 1
                return new_unit_ann_dict
471
472 1
            def compute_aqs(aqs, work_unit_ann_dict, uqs_list, wqs_list, aqs_list, aqs_len, max_delta, avg_aqs_delta):
473
                """ compute annotation quality score (aqs) """
474 1
                aqs_new = Metrics.annotation_quality_score(list(aqs.keys()), work_unit_ann_dict, \
475
                                                        uqs_list[len(uqs_list) - 1], \
476
                                                        wqs_list[len(wqs_list) - 1])
477 1
                for ann, _ in aqs_new.items():
478 1
                    max_delta = max(max_delta, abs(aqs_new[ann] - aqs_list[len(aqs_list) - 1][ann]))
479 1
                    avg_aqs_delta += abs(aqs_new[ann] - aqs_list[len(aqs_list) - 1][ann])
480 1
                avg_aqs_delta /= aqs_len
481 1
                return aqs_new, max_delta, avg_aqs_delta
482
483 1
            def compute_uqs(uqs_new, unit_work_ann_dict, wqs_list, aqs_list, uqs_list, uqs_len, max_delta, avg_uqs_delta):
484
                """ compute unit quality score (uqs) """
485 1
                for unit_id, _ in unit_work_ann_dict.items():
486 1
                    uqs_new[unit_id] = Metrics.unit_quality_score(unit_id, unit_work_ann_dict, \
487
                                                                      wqs_list[len(wqs_list) - 1], \
488
                                                                      aqs_list[len(aqs_list) - 1])
489 1
                    max_delta = max(max_delta, \
490
                                abs(uqs_new[unit_id] - uqs_list[len(uqs_list) - 1][unit_id]))
491 1
                    avg_uqs_delta += abs(uqs_new[unit_id] - uqs_list[len(uqs_list) - 1][unit_id])
492 1
                avg_uqs_delta /= uqs_len
493 1
                return uqs_new, max_delta, avg_uqs_delta
494
495 1
            if not config.open_ended_task:
496
                # compute annotation quality score (aqs)
497 1
                aqs_new, max_delta, avg_aqs_delta = compute_aqs(aqs, work_unit_ann_dict, \
498
                                uqs_list, wqs_list, aqs_list, aqs_len, max_delta, avg_aqs_delta)
499
500
            # compute unit quality score (uqs)
501 1
            uqs_new, max_delta, avg_uqs_delta = compute_uqs(uqs_new, unit_work_ann_dict, \
502
                                    wqs_list, aqs_list, uqs_list, uqs_len, max_delta, avg_uqs_delta)
503
504
            # compute worker quality score (WQS)
505 1
            wwa_new, wsa_new, wqs_new, max_delta, avg_wqs_delta = compute_wqs(\
506
                        wwa_new, wsa_new, wqs_new, \
507
                        work_unit_ann_dict, unit_ann_dict, unit_work_ann_dict, wqs_list, \
508
                        uqs_list, aqs_list, wqs_len, max_delta, avg_wqs_delta)
509
510
            # save results for current iteration
511 1
            uqs_list.append(uqs_new.copy())
512 1
            wqs_list.append(wqs_new.copy())
513 1
            wwa_list.append(wwa_new.copy())
514 1
            wsa_list.append(wsa_new.copy())
515 1
            if not config.open_ended_task:
516 1
                aqs_list.append(aqs_new.copy())
0 ignored issues
show
introduced by
The variable aqs_new does not seem to be defined for all execution paths.
Loading history...
517 1
            iterations += 1
518
519 1
            unit_ann_dict = reconstruct_unit_ann_dict(unit_ann_dict, work_unit_ann_dict, wqs_new)
520
521 1
            logging.info(str(iterations) + " iterations; max d= " + str(max_delta) + \
522
                        " ; wqs d= " + str(avg_wqs_delta) + "; uqs d= " + str(avg_uqs_delta) + \
523
                        "; aqs d= " + str(avg_aqs_delta))
524
525 1
        def save_unit_ann_score(unit_ann_dict, unit_work_ann_dict, iteration_value):
526
            """ save the unit annotation score for print """
527 1
            uas = Counter()
528 1
            for unit_id in unit_ann_dict:
529 1
                uas[unit_id] = Counter()
530 1
                for ann in unit_ann_dict[unit_id]:
531 1
                    uas[unit_id][ann] = Metrics.unit_annotation_score(unit_id, \
532
                                                ann, unit_work_ann_dict, \
533
                                                iteration_value)
534 1
            return uas
535
536 1
        uas = save_unit_ann_score(unit_ann_dict, unit_work_ann_dict, wqs_list[len(wqs_list) - 1])
537 1
        uas_initial = save_unit_ann_score(unit_ann_dict, unit_work_ann_dict, wqs_list[0])
538
539 1
        results['units']['uqs'] = pd.Series(uqs_list[-1])
540 1
        results['units']['unit_annotation_score'] = pd.Series(uas)
541 1
        results['workers']['wqs'] = pd.Series(wqs_list[-1])
542 1
        results['workers']['wwa'] = pd.Series(wwa_list[-1])
543 1
        results['workers']['wsa'] = pd.Series(wsa_list[-1])
544 1
        if not config.open_ended_task:
545 1
            results['annotations']['aqs'] = pd.Series(aqs_list[-1])
546
547 1
        results['units']['uqs_initial'] = pd.Series(uqs_list[1])
548 1
        results['units']['unit_annotation_score_initial'] = pd.Series(uas_initial)
549 1
        results['workers']['wqs_initial'] = pd.Series(wqs_list[1])
550 1
        results['workers']['wwa_initial'] = pd.Series(wwa_list[1])
551 1
        results['workers']['wsa_initial'] = pd.Series(wsa_list[1])
552 1
        if not config.open_ended_task:
553 1
            results['annotations']['aqs_initial'] = pd.Series(aqs_list[1])
554
        return results
555