Je travaille avec des lignes individuelles de trames de données pandas, mais je trébuche sur des problèmes de coercition lors de l'indexation et de l'insertion de lignes. Les pandas semblent toujours vouloir contraindre d'un type mixte int / flottant à tous les types flottants, et je ne vois aucun contrôle évident sur ce comportement.
Par exemple, voici une simple trame de données avec a
comme int
et b
comme float
:
import pandas as pd
pd.__version__ # '0.25.2'
df = pd.DataFrame({'a': [1], 'b': [2.2]})
print(df)
# a b
# 0 1 2.2
print(df.dtypes)
# a int64
# b float64
# dtype: object
Voici un problème de coercition lors de l'indexation d'une ligne:
print(df.loc[0])
# a 1.0
# b 2.2
# Name: 0, dtype: float64
print(dict(df.loc[0]))
# {'a': 1.0, 'b': 2.2}
Et voici un problème de coercition lors de l'insertion d'une ligne:
df.loc[1] = {'a': 5, 'b': 4.4}
print(df)
# a b
# 0 1.0 2.2
# 1 5.0 4.4
print(df.dtypes)
# a float64
# b float64
# dtype: object
Dans les deux cas, je souhaite que la a
colonne reste en tant que type entier, plutôt que d'être contrainte à un type flottant.
df.loc[[0], df.columns]
.read_[type]
prend en charge plusieurs dtypes si ...Réponses:
Après quelques recherches, voici quelques solutions de contournement terriblement laides. (Une meilleure réponse sera acceptée.)
Une bizarrerie trouvée ici est que les colonnes non numériques arrêtent la coercition, alors voici comment indexer une ligne sur a
dict
:Et l'insertion d'une ligne peut être effectuée en créant un nouveau bloc de données avec une ligne:
Ces deux astuces ne sont pas optimisées pour les trames de données volumineuses, j'apprécierais donc grandement une meilleure réponse!
la source
df['a'] = df.a.astype(mytype)
... C'est quand même sale et probablement pas efficace..astype()
est dangereux pour float -> integer; il n'a aucun problème à se changer1.1
en1
, vous devez donc vraiment vous assurer que toutes vos valeurs sont de type entier avant de le faire. Il est probablement préférable d'utiliserpd.to_numeric
avecdowncast='integer'
La racine du problème est que
On peut voir ça:
Et une série ne peut avoir qu'un seul type, dans votre cas, int64 ou float64.
Deux solutions de contournement me viennent à l'esprit:
ou
https://github.com/pandas-dev/pandas/blob/master/pandas/core/frame.py#L6973
Donc, votre solution de contournement est en fait solide, sinon nous pourrions:
la source
object
des types de données! Un autre est de créer un objet DataFrame depuis le début:df = pd.DataFrame({'a': [1], 'b': [2.2]}, dtype=object)
Chaque fois que vous obtenez des données d'une trame de données ou que vous ajoutez des données à une trame de données et que vous devez conserver le même type de données, évitez la conversion vers d'autres structures internes qui ne connaissent pas les types de données nécessaires.
Lorsque vous le
df.loc[0]
convertissezpd.Series
,Et maintenant,
Series
n'en aura qu'un seuldtype
. Ainsi contraignantint
àfloat
.Au lieu de cela, conservez la structure
pd.DataFrame
,Sélectionnez la ligne requise comme cadre, puis convertissez-la en
dict
De même, pour ajouter une nouvelle ligne, utilisez la
pd.DataFrame.append
fonction pandas ,Ce qui précède ne provoquera pas de conversion de type,
la source
Une approche différente avec de légères manipulations de données:
Supposons que vous ayez une liste de dictionnaires (ou cadres de données)
lod=[{'a': [1], 'b': [2.2]}, {'a': [5], 'b': [4.4]}]
où chaque dictionnaire représente une ligne (notez les listes dans le deuxième dictionnaire). Ensuite, vous pouvez facilement créer une trame de données via:
et vous gérez les types de colonnes. Voir concat
Donc, si vous avez une trame de données et une liste de dict, vous pouvez simplement utiliser
la source
Dans le premier cas, vous pouvez travailler avec le type de données entier nullable . La sélection de la série n'est pas contrainte
float
et les valeurs sont placées dans unobject
conteneur. Le dictionnaire est ensuite correctement créé, avec la valeur sous-jacente stockée en tant quenp.int64
.Avec votre syntaxe, cela fonctionne presque aussi pour le deuxième cas, mais cela se transforme en
object
, donc pas génial:Cependant, nous pouvons apporter une petite modification à la syntaxe pour ajouter une ligne à la fin (avec un RangeIndex) et maintenant les types sont traités correctement.
la source