web-dev-qa-db-fra.com

python: convertit les données numériques d'un cadre de données de pandas en fichiers flottants en présence de chaînes

J'ai une base de données de pandas avec une colonne 'cap'. Cette colonne est principalement composée de floats mais contient quelques chaînes, par exemple à l'index 2.

df =
    cap
0    5.2
1    na
2    2.2
3    7.6
4    7.5
5    3.0
...

J'importe mes données depuis un fichier csv comme ceci:

df = DataFrame(pd.read_csv(myfile.file))

Malheureusement, lorsque je fais cela, la colonne 'cap' est importée entièrement en tant que chaîne. Je voudrais que les flotteurs soient identifiés comme flottants et les cordes comme des cordes. Essayer de convertir ceci en utilisant:

df['cap'] = df['cap'].astype(float)

génère une erreur:

could not convert string to float: na

Existe-t-il un moyen de transformer tous les nombres en flottants tout en conservant le "na" comme chaîne?

12
natsuki_2002

Voici une solution de contournement possible

d'abord, vous définissez une fonction qui convertit les nombres en nombre uniquement si nécessaire

 def to_number(s):
    try:
        s1 = float(s)
        return s1
    except ValueError:
        return s

et ensuite vous l'appliquez rangée par rangée.


Exemple:  

donné

 df 
     0
  0  a
  1  2

a et 2 sont des chaînes, nous effectuons la conversion via

converted = df.apply(lambda f : to_number(f[0]) , axis = 1)  

 converted
 0    a
 1    2

Un contrôle direct sur les types:

type(converted.iloc[0])                                                                                                                             
str

type(converted.iloc[1])                                                                                                                             
float
1
Acorbe

Les calculs avec des colonnes de type float64 (plutôt que d'objet) sont beaucoup plus efficaces, c'est donc préférable ... cela vous permettra également d'effectuer d'autres calculs. À cause de cela, il est recommandé d'utiliser NaN pour les données manquantes (plutôt que votre propre paramètre fictif ou Aucun).

Est-ce vraiment la réponse que vous voulez?

In [11]: df.sum()  # all strings
Out[11]: 
cap    5.2na2.27.67.53.0
dtype: object

In [12]: df.apply(lambda f: to_number(f[0]), axis=1).sum()  # floats and 'na' strings
TypeError: unsupported operand type(s) for +: 'float' and 'str'

Vous devriez utiliser convert_numeric pour contraindre à floats:

In [21]: df.convert_objects(convert_numeric=True)
Out[21]: 
   cap
0  5.2
1  NaN
2  2.2
3  7.6
4  7.5
5  3.0

Ou lisez-le directement en csv, en ajoutant 'na' à la liste des valeurs à considérer comme NaN:

In [22]: pd.read_csv(myfile.file, na_values=['na'])
Out[22]: 
   cap
0  5.2
1  NaN
2  2.2
3  7.6
4  7.5
5  3.0

Dans les deux cas, sum (et de nombreuses autres fonctions du pandas) fonctionnera désormais:

In [23]: df.sum()
Out[23]:
cap    25.5
dtype: float64

Comme Jeff conseille :

répéter 3 fois vite: objet == mauvais, float == bien

19
Andy Hayden

Tout d'abord, la manière dont vous importez votre fichier CSV est redondante, au lieu de:

df = DataFrame(pd.read_csv(myfile.file))

Vous pouvez faire directement:

df = pd.read_csv(myfile.file)

Puis convertir en float, et mettre tout ce qui n’est pas un nombre comme NaN:

df = pd.to_numeric(df, errors='coerce')
2
Victor Grau Serrat

J'ai essayé une alternative sur ce qui précède:

for num, item in enumerate(data['col']):
    try:
        float(item)
    except:
        data['col'][num] = nan
1
reabow