In [1]:
%matplotlib inline

import pymysql.cursors
import json
import pandas as pd

# Connect to the database
connection = pymysql.connect(host='localhost',
                             user='consultation',
                             password='consultation',
                             db='consultation',
                             charset='latin1',
                             cursorclass=pymysql.cursors.DictCursor)

In [108]:
results = []
affirmations = [
    "des analyses ou proposition d'ordre général",
    "des prises de position contre une mesure existante",
    "des prises de position en faveur d'une mesure existante",
    "des propositions de nouvelles mesures",
    "des questions ou demandes d'information",
    "l'évocation d'expérience(s) personnelle(s)",
    "une analyse des causes du problème",
    "une description d'un problème"]

affirmations_short = [
    'analyse ou proposit°',
    'contre 1 mesure',
    'pour 1 mesure',
    'nouvelles mesures',
    'questions',
    'XP personnelle',
    'analyse des causes',
    'description pb'
]
usage = ["cite", "prend en compte", "recois", "rien", "éclaircir"]
usage_label = ["cite", "prend en compte", "reçoit", "ne fait rien", "demande à éclaircir"]
def build_result(row):
    data = json.loads(row['data'])
    if type(data) != str:
        if 'affirmations' in data:
            row['affirmations'] = data['affirmations']
            for p, p_short in zip(affirmations, affirmations_short):
                if p in data['affirmations']:
                    row[p_short] = 1
                else:
                    row[p_short] = 0
                
        if 'original' in data:
            row['original'] = 1 if "oui" in data['original'] else 0
        
        if 'usage' in data :
            for p, p_label in zip(usage, usage_label):
                if p in data['usage']:
                    row[p_label] = 1
                else:
                    row[p_label] = 0
            
    row.pop('data')
    return row
    
with connection.cursor() as cursor:
    sql = "SELECT `document_id`, `data`, documents.source, documents.theme, documents.question, documents.text FROM `tasks` INNER JOIN `documents` ON documents.id = tasks.document_id"
    cursor.execute(sql)
    crowdsourced = [build_result(row) for row in cursor.fetchall()]

In [109]:
df = pd.DataFrame(data=crowdsourced)
df.fillna(0, inplace=True)
df.to_csv('crowdsourcing_consultation_an.csv', float_format='%.0f')
df.head()


Out[109]:
XP personnelle affirmations analyse des causes analyse ou proposit° cite contre 1 mesure demande à éclaircir description pb document_id ne fait rien nouvelles mesures original pour 1 mesure prend en compte question questions reçoit source text theme
0 0.0 [des analyses ou proposition d'ordre général, ... 0.0 1.0 1.0 0.0 0.0 0.0 339 0.0 1.0 1.0 0.0 0.0 Si vous avez d’autres informations ou expérien... 0.0 0.0 lpyWm20=/31 Sans rapport avec les pensions impayées mais e... 4
1 0.0 [des propositions de nouvelles mesures] 0.0 0.0 0.0 0.0 0.0 0.0 271 0.0 1.0 1.0 0.0 1.0 Si vous avez d’autres informations ou expérien... 0.0 0.0 lpyclm0=/26 L'élaboration d'un guide à destination des par... 3
2 0.0 [une description d'un problème, des propositio... 0.0 0.0 1.0 0.0 0.0 1.0 43 0.0 1.0 1.0 0.0 0.0 Si vous avez d’autres informations ou expérien... 0.0 0.0 lpyWlWc=/16 -faire connaître les dispositifs de signalemen... 2
3 0.0 [des propositions de nouvelles mesures] 0.0 0.0 0.0 0.0 0.0 0.0 74 0.0 1.0 0.0 0.0 1.0 Si vous avez d’autres informations ou expérien... 0.0 0.0 lpyYl2Y=/16 Programmer des dessins animés pour le public e... 2
4 1.0 [l'évocation d'expérience(s) personnelle(s), u... 1.0 0.0 0.0 0.0 0.0 0.0 519 0.0 0.0 0.0 0.0 1.0 Si vous avez d’autres informations ou expérien... 0.0 0.0 lp2VlGY=/40 Simplement que l'on écoute les femmes lorsqu'e... 5

Éléments des contributions identifiés par les rapporteurs


In [110]:
affirmations_total = df[affirmations_short].sum() / df.shape[0]
affirmations_total.sort_values(ascending=False, inplace=True)
plot = affirmations_total.plot(
    kind='bar',
    title='Éléments identifiés par les rapporteurs')
plot.set_ylabel('Pourcentage de contributions')
affirmations_total.sum()


Out[110]:
1.168754998667022

Originalité des contributions


In [111]:
original = df[['original']].sum() / df.shape[0]
original


Out[111]:
original    0.288456
dtype: float64

Propos les + intéressants


In [112]:
usage_total = df[usage_label].sum() / df.shape[0]
usage_total.sort_values(inplace=True, ascending=False)
plot = usage_total.plot(
    kind='bar',
    title='Les actions à mener sur les contributions selon les rapporteurs')
plot.set_ylabel('Pourcentage de contributions')


Out[112]:
<matplotlib.text.Text at 0x7f5c5f24fc50>

Validation des contributions : quelle méthode ?


In [113]:
gp_by_document = df.groupby('document_id')
count_by_document = gp_by_document.document_id.count()
count_by_document.sort_values(ascending=False, inplace=True)
plot = count_by_document.plot(
    kind='hist',
    normed=True,
    title='Nombre de fois qu\'une contribution a été analysée')
plot.set_ylabel('Pourcentage des contributions')


Out[113]:
<matplotlib.text.Text at 0x7f5c5cf49b70>

In [114]:
def validation_method_1(data):
    # méthode en production : éléments + originalité
    return data[affirmations_short + ['original']].duplicated().sum() > 2

def validation_method_2(data):
    # seulement sur les éléments
    return data[affirmations_short].duplicated().sum() > 2

def validation_method_3(data):
    # ok si au moins un élement est retrouvé 3x + originalité
    for p in affirmations_short:
        if data[[p, 'original']].duplicated().sum() > 2:
            return True
        
    return False

score = {'method_1': 0, 'method_2': 0, 'method_3': 0}
document_count = len(df.document_id.unique())
for _, group in gp_by_document:
    if validation_method_1(group):
        score['method_1'] += 1 / document_count
    if validation_method_2(group):
        score['method_2'] += 1 / document_count
    if validation_method_3(group):
        score['method_3'] += 1 / document_count

In [115]:
plot = pd.DataFrame(data=[score]).plot(
    kind='bar',
    title='Pourcentage de contributions validées suivant les 3 méthodes')
plot.set_ylabel('Pourcentage des contributions validées')


Out[115]:
<matplotlib.text.Text at 0x7f5c5f402198>

In [116]:
score


Out[116]:
{'method_3': 0.6226175349428221,
 'method_2': 0.20203303684879334,
 'method_1': 0.07623888182973307}

Export des données crowdsourcées


In [141]:
#"cite", "prend en compte", "reçoit", "ne fait rien", "demande à éclaircir"
df['usage'] = df['reçoit'] * 5 + df['cite'] * 4 + df['demande à éclaircir'] * 3 + df['prend en compte'] * 2
resultat_crowdsource = df[['document_id','usage','original','analyse ou proposit°','contre 1 mesure','pour 1 mesure','nouvelles mesures','questions','XP personnelle','analyse des causes','description pb']].groupby('document_id').mean().sort_values(by='usage', ascending=False)
resultat_crowdsource['document_id'] = resultat_crowdsource.index
resultat_crowdsource.head()


Out[141]:
usage original analyse ou proposit° contre 1 mesure pour 1 mesure nouvelles mesures questions XP personnelle analyse des causes description pb document_id
document_id
623 4.500000 0.333333 0.166667 0.166667 0.0 0.500000 0.0 0.333333 0.500000 0.666667 623
708 4.333333 1.000000 0.000000 0.000000 0.0 1.000000 0.0 0.000000 0.000000 0.000000 708
669 4.250000 0.750000 0.250000 0.250000 0.0 0.000000 0.0 1.000000 0.250000 0.750000 669
507 4.200000 1.000000 0.200000 0.000000 0.0 0.800000 0.0 0.000000 0.400000 0.600000 507
219 4.000000 0.500000 0.500000 0.000000 0.0 0.166667 0.0 0.000000 0.166667 0.666667 219

In [3]:
with connection.cursor() as cursor:
    sql = "SELECT id as document_id, source, theme, question, text FROM documents"
    cursor.execute(sql)
    documents = pd.DataFrame(data=cursor.fetchall())
documents.index = documents['document_id']
documents.head()


Out[3]:
document_id question source text theme
document_id
1 1 Si vous avez d’autres informations ou expérien... lpucnGQ=/16 le langage, la tenue et une certaine façon de ... 2
2 2 Si vous avez d’autres informations ou expérien... lpucnG0=/16 une campagne d'information sur le poids de tou... 2
3 3 Si vous avez d’autres informations ou expérien... lpudk2k=/16 Montrer des documentaires sur le role femmes-h... 2
4 4 Si vous avez d’autres informations ou expérien... lpudlGc=/16 que le gouvernement et les pouvoirs publics co... 2
5 5 Si vous avez d’autres informations ou expérien... lpudlWU=/16 Dans les médias, trop de commentaires sur le p... 2

In [162]:
documents_crowdsource = documents.merge(right=resultat_crowdsource,right_on='document_id', left_on='document_id')
documents_crowdsource.sort_values(by='usage', ascending=False, inplace=True)
documents_crowdsource.to_csv('crowdsource_resultat_analyses.csv')
documents_crowdsource.head()


Out[162]:
document_id question source text theme usage original analyse ou proposit° contre 1 mesure pour 1 mesure nouvelles mesures questions XP personnelle analyse des causes description pb
592 623 Si vous avez d’autres informations ou expérien... lp2XmWo=/40 Juriste dans un CIDFF, je pense que l'ordonnan... 5 4.500000 0.333333 0.166667 0.166667 0.0 0.500000 0.0 0.333333 0.500000 0.666667
677 708 Si vous avez d’autres informations ou expérien... lp2ammQ=/16 Pourquoi à l'image des marques qui s'allouent ... 2 4.333333 1.000000 0.000000 0.000000 0.0 1.000000 0.0 0.000000 0.000000 0.000000
638 669 Si vous avez d’autres informations ou expérien... lp2ZlGU=/40 Grande difficultés pour obtenir des ordonnance... 5 4.250000 0.750000 0.250000 0.250000 0.0 0.000000 0.0 1.000000 0.250000 0.750000
478 507 Si vous avez d’autres informations ou expérien... lpydnGk=/40 L'automatisation des relevés d'eau, de gaz ou ... 5 4.200000 1.000000 0.200000 0.000000 0.0 0.800000 0.0 0.000000 0.400000 0.600000
208 219 Si vous avez d’autres informations ou expérien... lpyVk2g=/26 Ce droit devrait pouvoir être utilisé comme n'... 3 4.000000 0.500000 0.500000 0.000000 0.0 0.166667 0.0 0.000000 0.166667 0.666667

In [4]:
with connection.cursor() as cursor:
    sql = "SELECT document_id, synthese FROM tasks WHERE length(synthese) > 3"
    cursor.execute(sql)
    syntheses = pd.DataFrame(data=cursor.fetchall())
syntheses['affirmation'] = syntheses[syntheses['synthese'] != '']['synthese'].apply(lambda s: s.split(' : ')[0])
syntheses['synthese'] = syntheses[syntheses['synthese'] != '']['synthese'].apply(lambda s: " : ".join(s.split(' : ')[1:]))
documents_crowdsource = documents.merge(right=syntheses,right_on='document_id', left_on='document_id')
documents_crowdsource.to_csv('crowdsource_resultat_syntheses.csv')
documents_crowdsource['synthese'] = documents_crowdsource['synthese']+" "
documents_crowdsource.head()


Out[4]:
document_id question source text theme synthese affirmation
0 2 Si vous avez d’autres informations ou expérien... lpucnG0=/16 une campagne d'information sur le poids de tou... 2 Des campagnes d'information sur les stéréotypes des analyses ou proposition d'ordre général
1 2 Si vous avez d’autres informations ou expérien... lpucnG0=/16 une campagne d'information sur le poids de tou... 2 Relever les remarques sexistes "bienveillantes... une description d'un problème
2 2 Si vous avez d’autres informations ou expérien... lpucnG0=/16 une campagne d'information sur le poids de tou... 2 Information sur les réflexions sexistes au quo... des analyses ou proposition d'ordre général
3 3 Si vous avez d’autres informations ou expérien... lpudk2k=/16 Montrer des documentaires sur le role femmes-h... 2 Montrer le modèle scandinave de l'égalité homm... des propositions de nouvelles mesures
4 3 Si vous avez d’autres informations ou expérien... lpudk2k=/16 Montrer des documentaires sur le role femmes-h... 2 Montrer des documentaires rôle homes/femme des... des propositions de nouvelles mesures

TFIDF

On réunit tous les textes dans un même champs


In [13]:
documents_crowdsource['synthese'] = documents_crowdsource['synthese']+". "
documents_text = documents_crowdsource[['document_id','synthese']].groupby('document_id').sum()
documents_text['text'] = documents['text']
documents_text['tout'] = documents['text']+' BR '+documents_text['synthese']
documents_text['document_id'] = documents_text.index
documents_text = pd.DataFrame(data=documents_text.values, columns=['synthese', 'text','tout', 'document_id'])
documents_text.head()


Out[13]:
synthese text tout document_id
0 Des campagnes d'information sur les stéréotype... une campagne d'information sur le poids de tou... une campagne d'information sur le poids de tou... 2
1 Montrer le modèle scandinave de l'égalité homm... Montrer des documentaires sur le role femmes-h... Montrer des documentaires sur le role femmes-h... 3
2 Création d'une "théorie du genre" qui n'existe... que le gouvernement et les pouvoirs publics co... que le gouvernement et les pouvoirs publics co... 4
3 Dans les médias, on commente le physique des f... Dans les médias, trop de commentaires sur le p... Dans les médias, trop de commentaires sur le p... 5
4 Sensibilisation des jeunes et des parents sur ... Sensibiliser les jeunes aux stéréotypes, et co... Sensibiliser les jeunes aux stéréotypes, et co... 8

TFIDF avec stop words français :


In [17]:
from sklearn.feature_extraction.text import TfidfVectorizer
corpus = documents_text['tout']
vectorizer = TfidfVectorizer(min_df=1, ngram_range=(1, 3), stop_words=[ 'BR', "alors", "au", "aucuns", "aussi", "autre", "avant", "avec", "avoir", "bon", "car", "ce", "cela", "ces", "ceux", "chaque", "ci", "comme", "comment", "dans", "des", "du", "dedans", "dehors", "depuis", "devrait", "doit", "donc", "dos", "début", "elle", "elles", "en", "encore", "essai", "est", "et", "eu", "fait", "faites", "fois", "font", "hors", "ici", "il", "ils", "je", "juste", "la", "le", "les", "leur", "là", "ma", "maintenant", "mais", "mes", "mine", "moins", "mon", "mot", "même", "ni", "nommés", "notre", "nous", "ou", "où", "par", "parce", "pas", "peut", "peu", "plupart", "pour", "pourquoi", "quand", "que", "quel", "quelle", "quelles", "quels", "qui", "sa", "sans", "ses", "seulement", "si", "sien", "son", "sont", "sous", "soyez", "sujet", "sur", "ta", "tandis", "tellement", "tels", "tes", "ton", "tous", "tout", "trop", "très", "tu", "voient", "vont", "votre", "vous", "vu", "ça", "étaient", "état", "étions", "été", "être"])
X = vectorizer.fit_transform(corpus)
X = vectorizer.fit_transform(documents_text['text'])
idf = vectorizer.idf_

tfidf = pd.DataFrame(data=list(zip(vectorizer.get_feature_names(), idf)), columns=['mot', 'interet'])
mots = tfidf[tfidf['interet'] > 3].sort_values(by='interet', ascending=False)['mot']

tfidf.sort_values(by='interet', ascending=False).head()


Out[17]:
mot interet
23417 lorsque réseau social 6.451038
30459 places crèches 6.451038
30449 place une enquête 6.451038
30450 place une garantie 6.451038
30451 place une véritable 6.451038

In [18]:
documents_mots = pd.DataFrame(data=X.todense(), columns=vectorizer.get_feature_names())
documents_mots.head()


Out[18]:
000 000 de 000 de part 000 euros 000 euros réclame 000 hommes 000 hommes ont 000 places 000 places territoire 000 période ... évolués de égalité évoquez évoquez conjoint évoquez conjoint de événements événements sportifs événements sportifs sanctionner êtres êtres envisageables êtres envisageables plutôt
0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
4 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0

5 rows × 46835 columns


In [19]:
documents_mots[mots.values].sum().sort_values(ascending=False)


Out[19]:
enfant                      3.801990
contre                      3.289735
pension                     3.020577
non                         2.999796
leurs                       2.919657
victime                     2.830871
père                        2.827454
soit                        2.792855
souvent                     2.786766
homme                       2.783594
congé                       2.749841
égalité                     2.737358
vie                         2.706611
parent                      2.687884
ont                         2.687600
sexistes                    2.670444
ai                          2.657657
de violences                2.635808
violence                    2.630323
bien                        2.627191
cette                       2.617777
médias                      2.584312
temps                       2.573354
faudrait                    2.572733
parents                     2.570099
travail                     2.563589
conjoint                    2.561477
exemple                     2.550920
place                       2.474119
mère                        2.430922
                              ...   
cohabitation forcee fils    0.032647
prendre maison              0.032647
prendre maison argent       0.032647
sois                        0.032647
fils partis                 0.032647
partis etudier ailleurs     0.032647
fils chats                  0.032647
ne oblige me                0.032647
fils charge                 0.032647
fils charge ne              0.032647
fils chats chiens           0.032647
fils partis etudier         0.032647
ne oblige                   0.032647
fils doublé                 0.032647
fils doublé surface         0.032647
partis etudier              0.032647
ne revienne installer       0.032647
semaine mois                0.032647
verse pere qu               0.032647
fils plus charge            0.032647
ne revienne                 0.032647
fin 2013                    0.032647
fin 2013 sommes             0.032647
fin 2015                    0.032647
fin 2015 assurais           0.032647
ne resterait rien           0.032647
ne resterait                0.032647
fevrier                     0.032647
fevrier 2015                0.032647
presque rien                0.032647
dtype: float64

In [13]:


In [ ]: