Per cada parell de frases, eliminar les anotacions que es diferencien de >1 de la mitjana i presenta un report dels exclosos. També fa un filtre de les anotacions disperes en presenta un informe al terminal. Imprimeix els parells de frases amb anotacions disperses en un document per fer-le la revisió manual. Calcula les correlacions, les imprimeix al terminal i en fa un report en html. Imprimeix un document .tsv amb totes les dades i un altre amb la nostra ground truth
# importacions
import pandas as pd
import seaborn as sns
sns.set(style="ticks", context="talk")
# llegim el dataset original com a dataframe
df = pd.read_csv("/STS/analisi/COMPLET4anotadors.tsv", delimiter="\t")
# Calculem les mitjanes dels anotadors, que farem servir més endavant
df["avg"] = df[["m47_1", "m47_2", "trad_1","trad_2"]].mean(axis=1)
# Creem la columna amb la mitjana definitiva i la llista d'exclosos, i els assignem un valor per defecte
df["newavg"] = df["avg"]
df["annotators_excluded"] = "no"
df["sentences_excluded"] = "no"
# fem una llista d'anotadors
anotadors = ["m47_1", "m47_2", "trad_1","trad_2"]
Aquest bloc té dues parts i dos objectius: Detectar si un anotador s'ha despistat o si les anotacions són disperses. 1) Primer mira si un anotador se separa massa dels altres. Si és així, entenem que l'anotador s'ha equivocat i que es pot descartar la seva anotació. Per fer-ho, comprova per cada anotador si se separa de més d'un punt de la mitjana d'anotacions. Si és el cas, l'elimina, torna a calcular la mitjana sense ell i l'anota a la llista d'anotadors exclosos Finalment, copia la nova mitjana a la columna "newavg" i la llista d'anotadors exclosos a la columna "annotators_excluded"
2) Després detecta les anotacions "dispereses", en que els anotadors es divideixen en dos blocs separats per dos punts (per exemple, 1, 1, 3, 3) o més (1, 1, 3, 4). En aquest cas, entenem que el parell de frases és ambigu i que es pot descartar. Per fer-ho, compara els anotadors un a un. Per 4 anotadors, fa sis comparatives. En les frases amb anotacions disperses, d'aquestes sis comparatives, o bé quatre vegades el valor és 2 o bé dues vegades el valor és 2 i dues o més vegades és 3 o més. Comprovem si es dona el cas i, sí és així, marquem el parell de frases com a descartable.
# fer cada fila de la llista, amb número k i dades com a sèrie de row:
for k,row in df.iterrows():
# creem les variables per detectar les disperses
dos = 0
tresomes = 0
menysdedos = 0
# fem la llista d'anotadors amb la que calcularem la mitjana
anotadors_mitjana = list(anotadors)
# i una altra que farem servir per comparar les anotacions
ant_comparar = list(anotadors)
# aquí apuntarem els anotadors eliminats
removed = []
#per cada anotador ...
for ant in anotadors:
#calcula la diferència entre la seva anotació i la mitjana dels altres
difavg = abs(row.get(ant)-row.avg)
if difavg > 1:
#si la diferència és més d'1, el traiem de la llista
anotadors_mitjana.remove(ant)
# registrem l'anotador exclòs
removed.append(ant)
# també comparem la seva anotació amb la dels altres
ant_comparar.remove(ant)
for a in ant_comparar:
va = abs(int(df.loc[k,[ant]]) - int(df.loc[k,[a]]))
if va == 2:
dos += 1
elif va >= 3:
tresomes += 1
else:
menysdedos += 1
# si es crea alguna d'aquestes dues situaciones és que l'anotació és dispersa
# s'avisa a "revisar"
if (dos == 2 and tresomes >= 2) or dos == 4:
df.at[k,"sentences_excluded"] = "excluded"
# quan ja han passat tots els anotadors, recalculem la mitjana amb els que queden a annos_list
newavg = round(row[anotadors_mitjana].mean(),2)
#guardem la mitjana a la colunna que correspon
df.loc[k,"newavg"] = newavg
# i guardem també la llista d'exclosos
df.at[k,"annotators_excluded"] = removed
Imprimim el df amb la mitajana, la nova mitjana i el llistat d'exclosos
df[["m47_1", "m47_2", "trad_1","trad_2","avg", "newavg", "annotators_excluded"]]
| m47_1 | m47_2 | trad_1 | trad_2 | avg | newavg | annotators_excluded | |
|---|---|---|---|---|---|---|---|
| 0 | 4 | 4 | 5 | 4 | 4.25 | 4.25 | [] |
| 1 | 4 | 4 | 5 | 5 | 4.50 | 4.50 | [] |
| 2 | 5 | 4 | 4 | 4 | 4.25 | 4.25 | [] |
| 3 | 3 | 2 | 1 | 1 | 1.75 | 1.33 | [m47_1] |
| 4 | 3 | 3 | 3 | 2 | 2.75 | 2.75 | [] |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 3074 | 3 | 2 | 1 | 2 | 2.00 | 2.00 | [] |
| 3075 | 3 | 2 | 2 | 4 | 2.75 | 2.33 | [trad_2] |
| 3076 | 3 | 3 | 3 | 3 | 3.00 | 3.00 | [] |
| 3077 | 3 | 2 | 3 | 2 | 2.50 | 2.50 | [] |
| 3078 | 2 | 2 | 1 | 1 | 1.50 | 1.50 | [] |
3079 rows × 7 columns
Fem l'estadística d'exclosos
print("Exclosos:")
print(df["annotators_excluded"].value_counts())
Exclosos: [] 2678 [trad_2] 182 [m47_1] 103 [trad_1] 52 [m47_2] 35 [m47_2, trad_2] 8 [m47_1, trad_1] 4 [m47_1, trad_2] 4 [m47_1, m47_2, trad_1] 3 [m47_1, m47_2] 3 [m47_1, m47_2, trad_2] 2 [m47_1, m47_2, trad_1, trad_2] 2 [trad_1, trad_2] 2 [m47_2, trad_1] 1 Name: annotators_excluded, dtype: int64
Presentem la llista de parell de frases que es proposa exloure
rslt_df = df[df["sentences_excluded"] == "excluded"]
print("Frases amb anotació dispersa:")
#print(rslt_df[["id", "m47_1", "m47_2", "trad_1","trad_2", "newavg", "annotators_excluded"]])
print("")
print("")
revisar_df = rslt_df[["id", "sentence 1", "sentence 2", "m47_1", "m47_2", "trad_1", "trad_2"]]
rslt_df[["id", "m47_1", "m47_2", "trad_1","trad_2", "newavg", "annotators_excluded"]]
Frases amb anotació dispersa:
| id | m47_1 | m47_2 | trad_1 | trad_2 | newavg | annotators_excluded | |
|---|---|---|---|---|---|---|---|
| 14 | ACN2_1010 | 3 | 3 | 1 | 1 | 2.0 | [] |
| 36 | ACN2_1030 | 3 | 3 | 1 | 1 | 2.0 | [] |
| 130 | ACN2_1115 | 3 | 3 | 1 | 1 | 2.0 | [] |
| 151 | ACN2_1134 | 3 | 3 | 1 | 1 | 2.0 | [] |
| 164 | ACN2_1146 | 3 | 3 | 1 | 1 | 2.0 | [] |
| 177 | ACN2_1158 | 3 | 3 | 1 | 1 | 2.0 | [] |
| 180 | ACN2_1160 | 3 | 3 | 1 | 0 | 1.0 | [m47_1, m47_2, trad_2] |
| 362 | ACN2_230 | 5 | 2 | 5 | 3 | 3.0 | [m47_1, m47_2, trad_1] |
| 407 | ACN2_271 | 2 | 4 | 2 | 4 | 3.0 | [] |
| 432 | ACN2_294 | 3 | 1 | 1 | 3 | 2.0 | [] |
| 582 | ACN2_429 | 3 | 3 | 1 | 1 | 2.0 | [] |
| 685 | ACN2_521 | 3 | 3 | 1 | 1 | 2.0 | [] |
| 790 | ACN2_616 | 5 | 2 | 2 | 4 | 4.0 | [m47_1, m47_2, trad_1] |
| 830 | ACN2_652 | 2 | 2 | 4 | 4 | 3.0 | [] |
| 902 | ACN2_717 | 3 | 3 | 1 | 1 | 2.0 | [] |
| 1014 | ACN2_818 | 3 | 3 | 1 | 1 | 2.0 | [] |
| 1085 | ACN2_882 | 2 | 2 | 0 | 0 | 1.0 | [] |
| 1145 | ACN2_937 | 3 | 3 | 1 | 1 | 2.0 | [] |
| 1185 | ACN2_973 | 3 | 3 | 1 | 1 | 2.0 | [] |
| 1214 | Oscar2_1 | 3 | 3 | 0 | 1 | 1.0 | [m47_1, m47_2, trad_1] |
| 1262 | Oscar2_142 | 2 | 2 | 0 | 0 | 1.0 | [] |
| 1297 | Oscar2_174 | 5 | 3 | 3 | 5 | 4.0 | [] |
| 1309 | Oscar2_185 | 2 | 2 | 0 | 0 | 1.0 | [] |
| 1360 | Oscar2_230 | 2 | 2 | 0 | 0 | 1.0 | [] |
| 1397 | Oscar2_264 | 2 | 2 | 4 | 4 | 3.0 | [] |
| 1437 | Oscar2_30 | 2 | 2 | 0 | 0 | 1.0 | [] |
| 1465 | Oscar2_325 | 4 | 2 | 2 | 4 | 3.0 | [] |
| 1492 | Oscar2_35 | 3 | 5 | 3 | 5 | 4.0 | [] |
| 1514 | Oscar2_37 | 2 | 2 | 4 | 4 | 3.0 | [] |
| 1516 | Oscar2_371 | 3 | 3 | 1 | 1 | 2.0 | [] |
| 1518 | Oscar2_373 | 4 | 2 | 2 | 4 | 3.0 | [] |
| 1612 | Oscar2_458 | 2 | 2 | 0 | 0 | 1.0 | [] |
| 1614 | Oscar2_46 | 3 | 3 | 5 | 5 | 4.0 | [] |
| 1615 | Oscar2_460 | 3 | 3 | 1 | 1 | 2.0 | [] |
| 1679 | Oscar2_518 | 4 | 2 | 2 | 4 | 3.0 | [] |
| 1742 | Oscar2_575 | 2 | 2 | 4 | 4 | 3.0 | [] |
| 1747 | Oscar2_58 | 2 | 4 | 2 | 4 | 3.0 | [] |
| 1749 | Oscar2_581 | 2 | 0 | 2 | 0 | 1.0 | [] |
| 1908 | Oscar2_73 | 2 | 5 | 3 | 5 | 3.0 | [m47_1, m47_2, trad_2] |
| 1948 | TE2_110 | 2 | 0 | 2 | 4 | 2.0 | [m47_2, trad_2] |
| 1968 | TE2_13 | 3 | 3 | 5 | 5 | 4.0 | [] |
| 2068 | TE2_220 | 2 | 2 | 0 | 0 | 1.0 | [] |
| 2550 | Viqui2_442 | 3 | 1 | 3 | 1 | 2.0 | [] |
| 2776 | Viqui2_646 | 2 | 0 | 2 | 0 | 1.0 | [] |
| 2909 | Viqui2_766 | 2 | 0 | 2 | 0 | 1.0 | [] |
print("CORRELACIONS")
print("")
for ant in anotadors:
print("- CORRELACIONS", ant)
print("Amb average:", df[ant].corr(df["avg"]))
print("Amb new average:", df[ant].corr(df["newavg"]))
print("")
CORRELACIONS - CORRELACIONS m47_1 Amb average: 0.8147645586878192 Amb new average: 0.8023045359514184 - CORRELACIONS m47_2 Amb average: 0.8600928734555362 Amb new average: 0.8604309525668924 - CORRELACIONS trad_1 Amb average: 0.9017306233150959 Amb new average: 0.9006445723772247 - CORRELACIONS trad_2 Amb average: 0.8661238362920517 Amb new average: 0.8274633017602278
print("Correlacions dels anotadors entre ells:")
dfc = df[["m47_1", "m47_2", "trad_1","trad_2"]]
correlation_df = dfc.corr()
correlation_df
Correlacions dels anotadors entre ells:
| m47_1 | m47_2 | trad_1 | trad_2 | |
|---|---|---|---|---|
| m47_1 | 1.000000 | 0.673893 | 0.654509 | 0.570730 |
| m47_2 | 0.673893 | 1.000000 | 0.711628 | 0.623529 |
| trad_1 | 0.654509 | 0.711628 | 1.000000 | 0.711383 |
| trad_2 | 0.570730 | 0.623529 | 0.711383 | 1.000000 |
# fem el dataset que publicarem
dataset_df = df[["id", "sentence 1", "sentence 2", "m47_1", "m47_2", "trad_1", "trad_2", "avg", "newavg", "annotators_excluded", "sentences_excluded"]]
t = open("sts_dataset.tsv", "w")
dataset_df.to_csv("sts_dataset.tsv", sep='\t')
t.close()
# preparem el dataframe amb el nostre ground truth
df_excl = df[df["sentences_excluded"] != "excluded"]
gt_df = df_excl[["id", "sentence 1", "sentence 2", "newavg"]]
gt_df = gt_df.rename({"newavg":"ground_truth"}, axis='columns')
gt_df
| id | sentence 1 | sentence 2 | ground_truth | |
|---|---|---|---|---|
| 0 | ACN2_1 | Jordi Cuixart i Carme Forcadell declararan en ... | Jordi Cuixart i Carme Forcadell declararan dim... | 4.25 |
| 1 | ACN2_10 | El 82,4% de les persones oculten de forma parc... | El 82,4% oculten de forma parcial o total que ... | 4.50 |
| 2 | ACN2_100 | Bonvehí respecta les declaracions de Junqueras... | Bonvehí respecta les declaracions de Junqueras... | 4.25 |
| 3 | ACN2_1000 | En l'acumulat dels primers onze mesos del 2016... | En els primers sis mesos de l'any l'increment ... | 1.33 |
| 4 | ACN2_1001 | Les matriculacions de les comarques lleidatane... | Les matriculacions de les comarques tarragonin... | 2.75 |
| ... | ... | ... | ... | ... |
| 3074 | Viqui2_95 | L'arxidiòcesi de Toronto és la major del Canadà. | Toronto és la ciutat més gran del Canadà i la ... | 2.00 |
| 3075 | Viqui2_96 | L'1 de gener de 1912, delegats de les provínci... | L'1 de gener de 1912, Sun havia proclamat ofic... | 2.33 |
| 3076 | Viqui2_97 | Unes pilastres separen verticalment les difere... | Unes pilastres que imiten carreus separen vert... | 3.00 |
| 3077 | Viqui2_98 | La Montesa Cota 25 fou un model de minimoto in... | La Montesa Cota 49 fou un model de ciclomotor ... | 2.50 |
| 3078 | Viqui2_99 | Desemboca a la platja de Ciutat Jardí al barri... | La ciutat de Palma li dedicà un carrer situat ... | 1.50 |
3034 rows × 4 columns
Creem un document amb el ground truth
t = open("sts_ground_truth.tsv", "w")
gt_df.to_csv("sts_ground_truth.tsv", sep='\t')
t.close()
Creem un document amb el dataset complet amb totes les informacions
t = open("sts_dataset.tsv", "w")
dataset_df.to_csv("sts_dataset.tsv", sep='\t')
t.close()
Imprimim també un report en html
from pandas_profiling import ProfileReport
profile = ProfileReport(df[["m47_1", "m47_2", "trad_1","trad_2","avg", "newavg"]], title="Pandas Profiling Report")
s = open("report.html","w")
s.write(profile.html)
s.close()
/home/carme/anaconda3/envs/spacy_antic/lib/python3.7/site-packages/pandas/core/frame.py:4446: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy errors=errors,