<jupyter_start><jupyter_text>Gender Biais detection  Application of the Bolukbasi Paper to the french    Quillivic Robin Sources : Man is to Computer Programmer as Woman is to Homemaker? Debiasing Word Embeddings, Bolukbasi, Tolga, 2016<jupyter_code>from gensim import *
from gensim.test.utils import common_texts, get_tmpfile
from gensim.models import Word2Vec
import logging
import gensim
import os

import itertools

from gensim.test.utils import get_tmpfile
from gensim.models import KeyedVectors

import matplotlib.pyplot as plt
from random import *

import pandas as pd
import numpy as np
import math

from sklearn.decomposition import PCA
import lib
import fasttext
from gensim.models.wrappers import FastText

from sklearn.metrics import roc_auc_score,accuracy_score
# Logging code taken from http://rare-technologies.com/word2vec-tutorial/
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)

# Load pre-trained Word2Vec model.
model  = gensim.models.KeyedVectors.load_word2vec_format(r'DATA\FR\cc.fr.300.vec', binary=False,limit=70000)
model_lem  = gensim.models.KeyedVectors.load_word2vec_format(r'DATA\FR\frWac_no_postag_no_phrase_500_skip_cut100.bin', binary=True,limit=70000)
#model  = gensim.models.KeyedVectors.load_word2vec_format(r'DATA\FR\fr_Kyubyong_wordvectors.vec',binary=False,limit=50000)
model_wiki  = gensim.models.KeyedVectors.load_word2vec_format(r'DATA\FR\wiki_fr.vec',binary=False,limit=70000)
model_wiki_lem  = gensim.models.KeyedVectors.load_word2vec_format('C:/Users/Robin/Documents/IMPACT/Notebooks/DATA/FR/ppmi_svd_fr/matrix.txt',binary=False,encoding='latin1')
# normalizeation :
model.init_sims(True)
model_lem.init_sims(True)
model_wiki.init_sims(True)
model_wiki_lem.init_sims(True)<jupyter_output>2019-03-13 15:07:24,928 : INFO : loading projection weights from DATA\FR\cc.fr.300.vec
2019-03-13 15:07:45,793 : INFO : loaded (70000, 300) matrix from DATA\FR\cc.fr.300.vec
2019-03-13 15:07:45,794 : INFO : loading projection weights from DATA\FR\frWac_no_postag_no_phrase_500_skip_cut100.bin
2019-03-13 15:07:47,163 : INFO : loaded (70000, 500) matrix from DATA\FR\frWac_no_postag_no_phrase_500_skip_cut100.bin
2019-03-13 15:07:47,183 : INFO : loading projection weights from DATA\FR\wiki_fr.vec
2019-03-13 15:08:10,811 : INFO : loaded (70000, 300) matrix from DATA\FR\wiki_fr.vec
2019-03-13 15:08:10,826 : INFO : loading projection weights from C:/Users/Robin/Documents/IMPACT/Notebooks/DATA/FR/ppmi_svd_fr/matrix.txt
2019-03-13 15:08:49,449 : INFO : loaded (53376, 500) matrix from C:/Users/Robin/Documents/IMPACT/Notebooks/DATA/FR/ppmi_svd_fr/matrix.txt
2019-03-13 15:08:49,467 : INFO : precomputing L2-norms of word weight vectors
2019-03-13 15:08:50,172 : INFO : precomputing L2-norms of word w[...]<jupyter_text>1) Find gender pair of word associated with gender<jupyter_code>def association_Genrator(w1,w2,model,top_n=1000):
    """
    return a data frame ordered by the most similar pair of the W1,W2
    """
    # we build a dataframe with the vocabulary
    df = pd.DataFrame(list(model.vocab.items()), columns=['word','count'])
    # we drop the index of the word entry
    k = df[df['word']==w1].index[0]
    j = df[df['word']==w2].index[0]
    liste = df['word'].drop([k,j]).values[:top_n]
    # we compute the length of the iteration to informethe user that the process could be long
    N=math.factorial(len(liste))/(math.factorial(len(liste)-2)*math.factorial(2))
    # init
    a = model[w1]-model[w2]
    S =[]
    P=[]
    i=0
    # we compute the similarity score
    for x in itertools.combinations(liste,2) :
        u = model[x[0]]-model[x[1]]
        S.append(lib.cosine_similarity(a,u))
        P.append(x)
        i+=1
        # print the progression
        if i%1000000==0:
            print(i/N*100,'%')
            
    # storing and ordering
    res = pd.DataFrame(data={'pair':P,'score':S})
    res['score'] = abs(res['score']) #get absolute value
    res = res.sort_values(by='score',ascending=False,inplace=False)
    return(res)
res_HF = association_Genrator('fille','garçon',model,top_n=1000)
res_HF.head(20)
res_HF = association_Genrator('le','la',model_wiki,top_n=1000)
res_HF.head(20)<jupyter_output><empty_output><jupyter_text>Comment :The gender pair generator we have built is not really meaningfull. We decided to create our own pair of word using our knowledge of French langage.We create :* **pair_g**: gender pairs associated with the determinants and pronoums* **pair_g1**: gender pairs associated with semantic signification* **pair_g2**: gender pairs associated with suffix<jupyter_code>pair_g = [['la','le'],['elle','il'], ['cette', 'cet'],
          ['une','un'],['laquelle', 'lequel'],['celle','celui'],['ma','mon'],
          ['mienne','mien'],['certaine', 'certain'],['aucune', 'aucun']
         ]

pair_g1 = [['fille','garçon'],['maman','papa'],['mère','père'],['fille','fils'],['femelle','mâle'],
           ['reine','roi'],['tante','oncle'],['grand-père','grand-mère'],
           ['femme','homme'],['soeur','frère'],['marraine','parrain']
          ]


pair_g2 = [['belle','beau'],['actrice','acteur'],['serveuse','serveur'],['contente' ,'content'],
           ['petite','petit'],['heureuse','heureux'],['gentille','gentils'],['seule', 'seul'],
           ['créatrice','créateur'],['chanteuse','chanteuse']]

pair_am = [['brebis', 'bélier'], ['chèvre', 'bouc'],['biche', 'cerf'],
           ['chatte', 'chat'], ['jument', 'cheval'],['chienne', 'chien'], ['poule', 'coq'],
           ['louve', 'loup'],['rate', 'rat'],['vache', 'taureau']]

pair_h =[['femme','homme'],['fille','garçon'],['femelle','mâle'],
         ['la','le'],['elle','il'],['une','un'],
         ['seule', 'seul'],['petite','petit'],
         ['jument', 'cheval'],['louve', 'loup']
        ]
pair_all= pair_g+pair_g1+pair_g2+pair_am+pair_h
#['ânesse', 'âne'],,['éléphante', 'éléphant'],['faisane', 'faisan'],,['hérissonne', 'hérisson'],
#['bufflonne', 'buffle'],['daime', 'daim'],['cane', 'canard'], ['dinde', 'dindon'],['chamelle', 'chameau'],
#['chevrette', 'chevreuil'],['crapaude', 'crapaud'],['hérone', 'héron'],['oie', 'jars'],['lapine', 'lapin']
#['hase', 'lièvre'],['tigresse', 'tigre']
#['lione', 'lion'],['merlette', 'merle'],['ourse', 'ours'],,['truie', 'cochon',['laie', 'sanglier'],<jupyter_output><empty_output><jupyter_text>1) Direct BiaisThanks to the function **from_pair_to_direction2** we compute the Gender direction depending on the pairs.<jupyter_code>#determunant and pronoum
direction_g0, expl_var_g0,eig_values_g0 = lib.from_pair_to_direction2(pair_g,model)
#semantic
direction_g1, expl_var_g1,eig_values_g1 = lib.from_pair_to_direction2(pair_g1,model)
# suffix
direction_g2, expl_var_g2,eig_values_g2 = lib.from_pair_to_direction2(pair_g2,model)
#mam
direction_gM, expl_var_gM,eig_values_gM = lib.from_pair_to_direction2(pair_am,model)
#hybride
direction_gh, expl_var_gh,eig_values_gh = lib.from_pair_to_direction2(pair_h,model)
# all
direction_gall, expl_var_gall,eig_values_gall = lib.from_pair_to_direction2(pair_all,model)
ax1 = lib.plot_var_eig(eig_values_g0,expl_var_g0)
ax1 = lib.plot_var_eig(eig_values_g1,expl_var_g1)
ax2 = lib.plot_var_eig(eig_values_g2,expl_var_g2)
axM = lib.plot_var_eig(eig_values_gM,expl_var_gM)
axh = lib.plot_var_eig(eig_values_gh,expl_var_gh)
axALL = lib.plot_var_eig(eig_values_gall,expl_var_gall)<jupyter_output><empty_output><jupyter_text>Exemple of  direct biais<jupyter_code>word = ['mathématique','football','amour','voiture','aventure','émotion','larme','danse','sein','robe','match']
print('#####################')
print('#    biaised Words   #')
print('#####################')
G,G1,G2,GM,GH,ALL = [],[],[],[],[],[]
for w in word :
    G.append( lib.cosine_similarity(model[w],direction_g0)*100)
    G1.append( lib.cosine_similarity(model[w],direction_g1)*100)
    G2.append( lib.cosine_similarity(model[w],direction_g2)*100)
    GM.append( lib.cosine_similarity(model[w],direction_gM)*100)
    GH.append( lib.cosine_similarity(model[w],direction_gh)*100)
    ALL.append( lib.cosine_similarity(model[w],direction_gall)*100)
res = pd.DataFrame(data={'Determinant':G,'famille':G1,'suffixe':G2,'Mammifères':GM,'Hybride':GH,'Toute':ALL},index=word)
res.plot.bar(figsize=(15,8))
plt.show()
neutral_fem =['table','chaise','pomme','banane','roue','enceinte','blague','bouteille','souris','feuille']
print('########################')
print('#    feminin Words      #')
print('########################')
G,G1,G2,GM,GH,ALL = [],[],[],[],[],[]
for w in neutral_fem :
    G.append( lib.cosine_similarity(model[w],direction_g0)*100)
    G1.append( lib.cosine_similarity(model[w],direction_g1)*100)
    G2.append( lib.cosine_similarity(model[w],direction_g2)*100)
    GM.append( lib.cosine_similarity(model[w],direction_gM)*100)
    GH.append( lib.cosine_similarity(model[w],direction_gh)*100)
    ALL.append( lib.cosine_similarity(model[w],direction_gall)*100)
res = pd.DataFrame(data={'Determinant':G,'famille':G1,'suffixe':G2,'Mammifères':GM,'Hybride':GH,'Toute':ALL},index=neutral_fem)
res.plot.bar(figsize=(15,8))
plt.show()
neutral_man =['stylo','kiwi','chocolat','café','véhicule','chateau','rire','casier','clavier','filtre']
print('########################')
print('#    masculin Words     #')
print('########################')
G,G1,G2,GM,GH,ALL = [],[],[],[],[],[]
for w in neutral_man :
    G.append( lib.cosine_similarity(model[w],direction_g0)*100)
    G1.append( lib.cosine_similarity(model[w],direction_g1)*100)
    G2.append( lib.cosine_similarity(model[w],direction_g2)*100)
    GM.append( lib.cosine_similarity(model[w],direction_gM)*100)
    GH.append( lib.cosine_similarity(model[w],direction_gh)*100)
    ALL.append( lib.cosine_similarity(model[w],direction_gall)*100)
res = pd.DataFrame(data={'Determinant':G,'famille':G1,'suffixe':G2,'Mammifères':GM,'Hybride':GH,'Toute':ALL},index=neutral_man)
res.plot.bar(figsize=(15,8))
plt.show()<jupyter_output>########################
#    masculin Words     #
########################<jupyter_text>First conclusion :We observe that the sign of the direct biais correspond to gramatical gender! Let's verify this hypothesis by implemented a classifier to infer the gramatical Gender.<jupyter_code>#Load lexique in a Dataframe
df = pd.read_excel(r'DATA\FR\Lexique382.xlsx',encoding='latin1')
def Gender_Classifier_predict(X,Pair,model):
    """
    predict the gender of a noum based on the 
    """
    direction_g, expl_var_g,eig_values_g = lib.from_pair_to_direction2(Pair,model)
    Y_pred = []
    for i in range(len(X)):
        if lib.cosine_similarity(X[i],direction_g)*100>0:
            Y_pred.append(0)
        else :
            Y_pred.append(1)
    return(Y_pred)

def store_score(pair,model,lexique):
    X,y = lib.built_X_y(lib.merge_model_lexique(df,model),model)
    Y_pred = Gender_Classifier_predict(X,pair,model)
    Y_pred_rand = np.random.randint(2, size=len(X))
    roc = roc_auc_score(y, Y_pred)
    acc = accuracy_score(y, Y_pred)
    roc_rand = roc_auc_score(y, Y_pred_rand)
    acc_rand = accuracy_score(y, Y_pred_rand)
    return(roc,acc,roc_rand,acc_rand)

def store_result(MODEL,MODEL_NAME,pair,lexique):
    ROC,ROC_R = [],[]
    ACC ,ACC_R = [],[]
    for model in MODEL:
        try :
            roc,acc,roc_rand,acc_rand = store_score(pair,model,lexique)
        except :
            #roc,acc,roc_rand,acc_rand = store_score(pair,model,lexique)
            roc,acc,roc_rand,acc_rand = 0,0,0,0
        ROC.append(roc)
        ACC.append(acc)
        ROC_R.append(roc_rand)
        ACC_R.append(acc_rand)
    df = pd.DataFrame(data = {'ROC':ROC,'ACC':ACC,'ROC_random':ROC_R,'ACC_Random':ACC_R},index=MODEL_NAME)
    return(df)<jupyter_output><empty_output><jupyter_text>We modify some of the pair to have some result with the lemmatized corpus<jupyter_code># we remind the pair here
pair_g = [['la','le'],['elle','il'], ['cette', 'cet'],
          ['une','un'],['laquelle', 'lequel'],['celle','celui'],['ma','mon'],
          ['mienne','mien'],['certaine', 'certain'],['aucune', 'aucun']
         ]

pair_g1 = [['femme','homme'],['maman','papa'],['mère','père'],['femelle','mâle'],
           ['reine','roi'],['tante','oncle'],
           ['fille','garçon'],['marraine','parrain']
          ]


pair_g2 = [['belle','beau'],['actrice','acteur'],['serveuse','serveur'],['contente' ,'content'],
           ['petite','petit'],['heureuse','heureux'],['gentille','gentils'],['seule', 'seul'],
           ['créatrice','créateur'],['chanteuse','chanteuse']]

pair_am = [['brebis', 'bélier'], ['chèvre', 'bouc'],['biche', 'cerf'],
            ['jument', 'cheval'], ['poule', 'coq'],
           ['louve', 'loup'],['rate', 'rat'],['vache', 'taureau']]

pair_h =[['femme','homme'],['fille','garçon'],['femelle','mâle'],
         ['la','le'],['elle','il'],
         ['jument', 'cheval'],['louve', 'loup']
        ]
pair_all= pair_g+pair_g1+pair_g2+pair_am+pair_h
print('##########################')
print('#    paires déterminant   #')
print('##########################')
MODEL = [model,model_lem,model_wiki,model_wiki_lem]
MODEL_NAME = ['model','model_lem','model_wiki','model_wiki_lem']
df_0 = store_result(MODEL,MODEL_NAME,pair_g,df)
df_0
print('######################')
print('#    paires famille   #')
print('######################')
MODEL = [model,model_lem,model_wiki,model_wiki_lem]
MODEL_NAME = ['model','model_lem','model_wiki','model_wiki_lem']
df_1 = store_result(MODEL,MODEL_NAME,pair_g1,df)
df_1
print('####################')
print('#    paires suffixe  #')
print('####################')
MODEL = [model,model_lem,model_wiki,model_wiki_lem]
MODEL_NAME = ['model','model_lem','model_wiki','model_wiki_lem']
df_2 = store_result(MODEL,MODEL_NAME,pair_g2,df)
df_2
print('##########################')
print('#    paires mamifères   #')
print('##########################')
MODEL = [model,model_lem,model_wiki,model_wiki_lem]
MODEL_NAME = ['model','model_lem','model_wiki','model_wiki_lem']
df_0 = store_result(MODEL,MODEL_NAME,pair_am,df)
df_0
print('##########################')
print('#    paires hybride      #')
print('##########################')
MODEL = [model,model_lem,model_wiki,model_wiki_lem]
MODEL_NAME = ['model','model_lem','model_wiki','model_wiki_lem']
df_0 = store_result(MODEL,MODEL_NAME,pair_h,df)
df_0
print('##########################')
print('#    paires all      #')
print('##########################')
MODEL = [model,model_lem,model_wiki,model_wiki_lem]
MODEL_NAME = ['model','model_lem','model_wiki','model_wiki_lem']
df_0 = store_result(MODEL,MODEL_NAME,pair_all,df)
df_0
print('############################')
print('#    Déterminants, familles #')
print('############################')
MODEL = [model,model_lem,model_wiki,model_wiki_lem]
MODEL_NAME = ['model','model_lem','model_wiki','model_wiki_lem']
df_01 = store_result(MODEL,MODEL_NAME,pair_g+pair_g1,df)
df_01
print('#############################')
print('#    détermiannt +suffixe  #')
print('#############################')
MODEL = [model,model_lem,model_wiki,model_wiki_lem]
MODEL_NAME = ['model','model_lem','model_wiki','model_wiki_lem']
df_02 = store_result(MODEL,MODEL_NAME,pair_g+pair_g2,df)
df_02
print('##############################')
print('#    Suffixe, famille, det #')
print('##############################')
MODEL = [model,model_lem,model_wiki,model_wiki_lem]
MODEL_NAME = ['model','model_lem','model_wiki','model_wiki_lem']
df_012 = store_result(MODEL,MODEL_NAME,pair_g+pair_g1+pair_g2,df)
df_012
 print('##############################')
print('#     famille, animaux  #')
print('##############################')
MODEL = [model,model_lem,model_wiki,model_wiki_lem]
MODEL_NAME = ['model','model_lem','model_wiki','model_wiki_lem']
df_012 = store_result(MODEL,MODEL_NAME,pair_g1+pair_am,df)
df_012<jupyter_output>##############################
#     famille, animaux  #
##############################
{'fraction_non_alphanumeric': 0.2225798308721444, 'fraction_numerical': 0.03104884513441878, 'mean_word_length': 6.560591603053435, 'pattern_counts': {'":': 0, '<': 26, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '427377', 'license': 'MIT', 'n_tokens_mistral': 6259, 'n_tokens_neox': 5916, 'n_words': 861, 'path': 'IMPACT_BOLUKBASI_Apply_to_French.ipynb', 'repo_name': 'binbin83/IMPACT', 'size': '15846'}