1
votes

conversion du rapport de chaîne en entier

J'ai une colonne qui se compose de rapports tels que 5: 2. Cependant, ces ratios sont sous forme de chaîne. J'en ai besoin sous forme de fraction. Comment puis je faire ça?

1       33 : 67
2       37 : 63
3       42 : 58
4       45 : 55
         ...   
2598    48 : 52
2599    36 : 64
2600          0
2601    28 : 72
2602    43 : 57
Name: female_male_ratio, Length: 2603, dtype: object


11 commentaires

Vous devriez regarder split() et int() .


Que signifie «forme de fraction»? Voulez-vous utiliser le type de Fraction bibliothèque standard? Ou vouliez-vous simplement une valeur float ? Ou autre chose?


Je veux qu'il soit flottant ou entier. Les deux fonctionneraient, mais je n'y arrivais pas.


Vous pouvez essayer df.replace(' : ', '/', regex=True).apply(pd.eval)


«45: 55» sera «9/11». Voulez-vous que la sortie pour cela soit (a) '9/11' (chaîne), (b) 1 (entier le plus proche) ou (c) 0.8181818181818182 (float)? (d) (9, 11) tuple d'entiers?


J'ai essayé ce df.replace(' : ', '/', regex=True).apply(pd.eval) mais il a soulevé une erreur de division zéro.


Je veux que ce soit un flotteur comme 0.8181 ou etc.


@AtillaColak Veuillez essayer ma réponse.


@MayankPorwal J'ai essayé votre code mais j'ai soulevé l'erreur suivante. `` ValueError: impossible de convertir float NaN en entier ''


@AtillaColak Pouvez-vous partager les données pour lesquelles cette erreur survient?


J'ai trouvé le problème. Le problème est qu'il y avait des valeurs nan, et je les ai remplies de zéros. Le code doit donc avoir une exception pour les moments où la valeur est zéro. Mais je ne sais pas comment.


5 Réponses :


1
votes

comme suggéré dans les commentaires, vous pouvez utiliser .split() et int() pour atteindre cet objectif:

def map_function(x):
    if len(x.split(':'))==2:
        return int(x.split(':')[0]) / int(x.split(':')[1]) 
    return int(x)
your_df['raito_column_name'] = your_df['raito_column_name'].apply(map_function)


5 commentaires

oui corrigé. mais la réponse @Wasif Hasan est plus performante que celle-ci .. vous suggérons de l'utiliser à la place ...


il n'en a probablement pas : c'est sa chaîne ...


nous supposons que vos données sont telles que vous les avez décrites


Oh je l'ai. Mais comment puis-je sauter des lignes avec une valeur 0. Peut-être en utilisant continuer. Pourriez-vous aider?


édité, j'ai ajouté une condition ...



0
votes

.str.split() avec .astype(int) , ici A est le nom de votre colonne

df['A'] = df['A'].str.split(':',expand=True)[0].astype(int)/df['A'].str.split(':',expand=True)[1].astype(int)


1 commentaires

J'ai essayé votre code mais j'ai causé une erreur. ValueError: cannot convert float NaN to integer



2
votes

Considérez votre df comme:

In [2039]: import numpy as np

In [2040]: df.col = df.col.str.split(':').str[0].astype(int).div(df.col.str.split(':').str[-1].astype(int)).replace(np.inf, np.nan) 

In [2041]: df
Out[2041]: 
        col
0  0.492537
1  0.587302
2  0.724138
3       NaN
4       NaN

Utilisez Series.str.split avec df.astype() :

In [2032]: df = pd.DataFrame({'col':['33 : 67', '37 : 63', '42 : 58', '0', '21 : 0']})

In [2033]: df
Out[2033]: 
       col
0  33 : 67
1  37 : 63
2  42 : 58
3        0
4   21 : 0

Remarque: Cela devrait gérer toutes les Zero Division errors ainsi que les cas où : n'est pas présent.


0 commentaires

0
votes

Vous pouvez utiliser extract avec regex et eval :

   ColA  ColB     ratio
0                      
1    33    67  0.492537
2    37    63  0.587302
3    42    58  0.724138
4    45    55  0.818182

Production:

import pandas as pd
import numpy as np

df = pd.read_clipboard(header=None, sep='\s\s\s\s+')

df = df.set_index(0)

df[1].str.extract('(\d+)\s:\s(\d+)')\
     .rename(columns={0:'ColA', 1:'ColB'})\
     .astype(int)\
     .eval('ratio = ColA / ColB')


0 commentaires

0
votes

Je pense que le simple vaut mieux que le complexe. Et la performance n'est pas trop mauvaise non plus. Le code est super simple: faites une boucle sur vos valeurs et faites un try .. except .. finally bloquer pour gérer tous les cas particuliers.

Performance

Comme référence, prenons les données ci-dessous (moins les ordures, car elles ne sont pas gérées par les autres réponses). La réponse la plus votée de Mayank Porwal est en 792µs :

       orig     float
0   33 : 67  0.492537
1   37 : 63  0.587302
2   42 : 58  0.724138
3   45 : 55  0.818182
4   48 : 52  0.923077
5   36 : 64  0.562500
6         0  0.000000
7   28 : 72  0.388889
8   43 : 57  0.754386
9    77 : 0       inf
10   -6 : 0      -inf
11  garbage       NaN

alors que cette réponse est plus de 80 fois plus rapide ( 9.53µs ):

import numpy as np
import pandas as pd

s = """33 : 67
37 : 63
42 : 58
45 : 55
48 : 52
36 : 64
      0
28 : 72
43 : 57
77 : 0
-6 : 0
garbage
"""

df = pd.DataFrame(dict(orig=s.strip().split("\n")))
df["float"] = get_vals(df["orig"].values)

Code

import numpy as np
import pandas as pd

def get_vals(input_vals):
    vals = []
    for x in input_vals:
        try:
            ints = [int(_) for _ in x.split(":")]
            val = ints[0] / ints[1]
        except IndexError:  # Handle cases where ":" is not present
            val = int(x)
        except ZeroDivisionError:  # Handle cases where divider is zero
            val = float("inf") if ints[0] > 0 else float("-inf")
        except ValueError:  # Handle all other cases
            val = np.nan
        finally:
            vals.append(val)
    return vals

Exemple

Exemple d'utilisation

In [8]: timeit get_vals(df["col"].values)
9.53 µs ± 27.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Exemple de sortie

In [5]: timeit df.col.str.split(':').str[0].astype(int).div(df.col.str.split(':').str[-1].astype(int)).replace(np.inf, np.nan)
792 µs ± 25 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)


0 commentaires