web-dev-qa-db-fra.com

Calculer le pourcentage de valeurs similaires dans pandas dataframe

J'ai un dataframe df, avec deux colonnes: Script (avec texte) et Speaker

Script  Speaker
aze     Speaker 1 
art     Speaker 2
ghb     Speaker 3
jka     Speaker 1
tyc     Speaker 1
avv     Speaker 2 
bhj     Speaker 1

Et j'ai la liste suivante: L = ['a','b','c']

Avec le code suivant,

df = (df.set_index('Speaker')['Script'].str.findall('|'.join(L))
        .str.join('|')
        .str.get_dummies()
        .sum(level=0))
print (df)

J'obtiens cette trame de données df2:

Speaker     a    b    c
Speaker 1   2    1    1
Speaker 2   2    0    0
Speaker 3   0    1    0

Quelle ligne puis-je ajouter dans mon code pour obtenir, pour chaque ligne de mon dataframe df2, un pourcentage de toutes les lignes prononcées par le locuteur, afin d'avoir la trame de données suivante df3:

Speaker     a    b    c
Speaker 1   50%  25%   25%
Speaker 2  100%    0   0
Speaker 3   0   100%   0
14
Alex Dana

Vous pouvez diviser par sum le long du premier axe, puis convertir en chaîne et ajouter %:

out = (df.set_index('Speaker')['Script'].str.findall('|'.join(L))
         .str.join('|')
         .str.get_dummies()
         .sum(level=0))

(out/out.sum(0)[:,None]).mul(100).astype(int).astype(str).add('%')

            a     b    c
Speaker                  
Speaker1   50%   25%  25%
Speaker2  100%    0%   0%
Speaker3    0%  100%   0%
8
yatu

À partir de votre trame de données d'origine, si vous voulez% et non la somme groupée des nuls, vous pouvez changer le script entier comme ci-dessous:

m = df.set_index('Speaker')['Script'].str.findall('|'.join(L)) #creates a list of matches
m = m.explode().reset_index() #explode to a series 
final = pd.crosstab(m['Speaker'],m['Script'],normalize='index').mul(100) # percentage pivot

Script         a      b     c
Speaker                      
Speaker 1   50.0   25.0  25.0
Speaker 2  100.0    0.0   0.0
Speaker 3    0.0  100.0   0.0

Si vous ne voulez pas du pourcentage, utilisez simplement:

pd.crosstab(m['Speaker'],m['Script'])

Script     a  b  c
Speaker           
Speaker 1  2  1  1
Speaker 2  2  0  0
Speaker 3  0  1  0

Remarque: cela utilise pandas 0.25+ comme version

5
anky_91
(df.set_index('Speaker')['Script'].str.extractall(f'({"|".join(L)})')
   .groupby('Speaker')[0].value_counts(normalize=True)
   .unstack(fill_value=0)
)

Production:

0            a     b     c
Speaker                   
Speaker 1  0.5  0.25  0.25
Speaker 2  1.0  0.00  0.00
Speaker 3  0.0  1.00  0.00
3
Quang Hoang

Étant donné l'exemple, vous pouvez essayer avec la ligne de code suivante:

df = (df/df.sum(axis=1)[:, None]).mul(100).astype(int)

Avec les données que vous fournissez:

import pandas as pd
import numpy as np
data = {'a':[2,2,0],'b':[1,0,1],'c':[1,0,0]}
df = pd.DataFrame(data)
df = (df/df.sum(axis=1)[:, None]).mul(100).astype(int)
print(df)

Production:

     a   b   c
0   50  25  25
1  100   0   0
2    0 100   0

Ou, si vous souhaitez ajouter le symbole '%':

df = (df / df.sum(axis=1)[:, None]).mul(100).astype(int).astype(str) + '%'

Production:

      a     b    c
0   50%   25%  25%
1  100%    0%   0%
2    0%  100%   0%
2
Celius Stingher