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
5 Réponses :
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)
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 ...
.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)
J'ai essayé votre code mais j'ai causé une erreur. ValueError: cannot convert float NaN to integer
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.
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')
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.
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)
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
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)
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)
Vous devriez regarder
split()
etint()
.Que signifie «forme de fraction»? Voulez-vous utiliser le type de
Fraction
bibliothèque standard? Ou vouliez-vous simplement une valeurfloat
? 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.