import pandas as pd

test_data = pd.read_csv("../data/relex-multiple-choice.csv")
test_data.head()

"""
Explanation: CrowdTruth for Multiple Choice Tasks: Relation Extraction
In this tutorial, we will apply CrowdTruth metrics to a multiple choice crowdsourcing task for Relation Extraction from sentences. The workers were asked to read a sentence with 2 highlighted terms, then pick from a multiple choice list what are the relations expressed between the 2 terms in the sentence. The task was executed on FigureEight. For more crowdsourcing annotation task examples, click here.
To replicate this experiment, the code used to design and implement this crowdsourcing annotation template is available here: template, css, javascript. 
This is a screenshot of the task as it appeared to workers:

A sample dataset for this task is available in this file, containing raw output from the crowd on FigureEight. Download the file and place it in a folder named data that has the same root as this notebook. Now you can check your data:
End of explanation
"""


import crowdtruth
from crowdtruth.configuration import DefaultConfig

"""
Explanation: Declaring a pre-processing configuration
The pre-processing configuration defines how to interpret the raw crowdsourcing input. To do this, we need to define a configuration class. First, we import the default CrowdTruth configuration class:
End of explanation
"""


class TestConfig(DefaultConfig):
    inputColumns = ["sent_id", "term1", "b1", "e1", "term2", "b2", "e2", "sentence"]
    outputColumns = ["relations"]
    
    annotation_separator = "\n"
    
    # processing of a closed task
    open_ended_task = False
    annotation_vector = [
        "title", "founded_org", "place_of_birth", "children", "cause_of_death",
        "top_member_employee_of_org", "employee_or_member_of", "spouse",
        "alternate_names", "subsidiaries", "place_of_death", "schools_attended",
        "place_of_headquarters", "charges", "origin", "places_of_residence",
        "none"]
    
    def processJudgments(self, judgments):
        # pre-process output to match the values in annotation_vector
        for col in self.outputColumns:
            # transform to lowercase
            judgments[col] = judgments[col].apply(lambda x: str(x).lower())
        return judgments

"""
Explanation: Our test class inherits the default configuration DefaultConfig, while also declaring some additional attributes that are specific to the Relation Extraction task:

inputColumns: list of input columns from the .csv file with the input data
outputColumns: list of output columns from the .csv file with the answers from the workers
annotation_separator: string that separates between the crowd annotations in outputColumns
open_ended_task: boolean variable defining whether the task is open-ended (i.e. the possible crowd annotations are not known beforehand, like in the case of free text input); in the task that we are processing, workers pick the answers from a pre-defined list, therefore the task is not open ended, and this variable is set to False
annotation_vector: list of possible crowd answers, mandatory to declare when open_ended_task is False; for our task, this is the list of relations
processJudgments: method that defines processing of the raw crowd data; for this task, we process the crowd answers to correspond to the values in annotation_vector

The complete configuration class is declared below:
End of explanation
"""


data, config = crowdtruth.load(
    file = "../data/relex-multiple-choice.csv",
    config = TestConfig()
)

data['judgments'].head()

"""
Explanation: Pre-processing the input data
After declaring the configuration of our input file, we are ready to pre-process the crowd data:
End of explanation
"""


results = crowdtruth.run(data, config)

"""
Explanation: Computing the CrowdTruth metrics
The pre-processed data can then be used to calculate the CrowdTruth metrics:
End of explanation
"""


results["units"].head()

"""
Explanation: results is a dict object that contains the quality metrics for sentences, relations and crowd workers.
The sentence metrics are stored in results["units"]:
End of explanation
"""


import matplotlib.pyplot as plt
%matplotlib inline

plt.hist(results["units"]["uqs"])
plt.xlabel("Sentence Quality Score")
plt.ylabel("Sentences")

"""
Explanation: The uqs column in results["units"] contains the sentence quality scores, capturing the overall workers agreement over each sentence. Here we plot its histogram:
End of explanation
"""


results["units"]["unit_annotation_score"].head()

"""
Explanation: The unit_annotation_score column in results["units"] contains the sentence-relation scores, capturing the likelihood that a relation is expressed in a sentence. For each sentence, we store a dictionary mapping each relation to its sentence-relation score.
End of explanation
"""


results["workers"].head()

"""
Explanation: The worker metrics are stored in results["workers"]:
End of explanation
"""


plt.hist(results["workers"]["wqs"])
plt.xlabel("Worker Quality Score")
plt.ylabel("Workers")

"""
Explanation: The wqs columns in results["workers"] contains the worker quality scores, capturing the overall agreement between one worker and all the other workers.
End of explanation
"""


results["annotations"]

results["units"].to_csv("../data/results/multchoice-relex-units.csv")
results["workers"].to_csv("../data/results/multchoice-relex-workers.csv")
results["annotations"].to_csv("../data/results/multchoice-relex-annotations.csv")

"""
Explanation: The relation metrics are stored in results["annotations"]. The aqs column contains the relation quality scores, capturing the overall worker agreement over one relation.
End of explanation
"""


