Я работаю с отдельными строками фреймов данных Pandas, но я спотыкаюсь о проблемах принуждения при индексации и вставке строк. Панды, кажется, всегда хотят привести к смешанному типу int / float к типам с плавающей точкой, и я не вижу каких-либо очевидных элементов управления этим поведением.
Например, вот простой фрейм данных с a
as int
и b
as 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
Вот проблема приведения при индексации одной строки:
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}
И вот проблема принуждения при вставке одной строки:
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
В обоих случаях я хочу, чтобы a
столбец оставался целочисленным типом, а не приводился к типу с плавающей точкой.
df.loc[[0], df.columns]
.read_[type]
хотя поддерживает несколько dtypes ...Ответы:
После некоторых копаний, вот несколько ужасных обходных путей. (Лучший ответ будет принят.)
Обнаруженная здесь причудливость заключается в том, что нечисловые столбцы прекращают приведение, поэтому вот как индексировать одну строку в
dict
:А вставить строку можно, создав новый фрейм данных с одной строкой:
Оба эти трюка не оптимизированы для больших фреймов данных, поэтому я был бы очень признателен за лучший ответ!
источник
df['a'] = df.a.astype(mytype)
... Он все еще грязный и, вероятно, не эффективный..astype()
опасно для числа с плавающей точкой -> целое число; он не имеет никаких проблем , изменяющийся1.1
в1
, так что вы действительно должны быть уверены , что все ваши ценности «целое число, как» прежде чем делать это. Вероятно, лучше всего использоватьpd.to_numeric
сdowncast='integer'
Корень проблемы в том, что
Мы видим, что:
И у серии может быть только один тип dtype, в вашем случае - int64 или float64.
В мою голову приходят два обходных пути:
или
https://github.com/pandas-dev/pandas/blob/master/pandas/core/frame.py#L6973
Так что ваш обходной путь на самом деле солидный, иначе мы могли бы:
источник
object
типы данных! Другой - создать объект DataFrame с самого начала:df = pd.DataFrame({'a': [1], 'b': [2.2]}, dtype=object)
Всякий раз, когда вы получаете данные из фрейма данных или добавляете данные в фрейм данных и вам необходимо сохранить тип данных таким же, избегайте преобразования в другие внутренние структуры, которые не знают о необходимых типах данных.
Когда вы сделаете
df.loc[0]
это превращается вpd.Series
,А сейчас
Series
останется только одинdtype
. Таким образом, принуждениеint
кfloat
.Вместо этого держите структуру как
pd.DataFrame
,Выберите строку, необходимую в качестве кадра, а затем преобразуйте в
dict
Точно так же, чтобы добавить новую строку, используйте
pd.DataFrame.append
функцию панд ,Вышеуказанное не приведет к преобразованию типов,
источник
Другой подход с небольшими манипуляциями с данными:
Предположим, у вас есть список словарей (или фреймов данных)
lod=[{'a': [1], 'b': [2.2]}, {'a': [5], 'b': [4.4]}]
где каждый словарь представляет строку (обратите внимание на списки во втором словаре). Затем вы можете легко создать фрейм данных с помощью:
и вы поддерживаете типы столбцов. Смотрите Конкат
Так что если у вас есть датафрейм и список диктовок, вы можете просто использовать
источник
В первом случае вы можете работать с типом данных NULL . Выбор Series не выполняется,
float
а значения помещаются вobject
контейнер. Затем словарь создается правильно, а базовое значение сохраняется какnp.int64
.С вашим синтаксисом это почти работает и для второго случая, но это повышается до
object
, так что не очень:Тем не менее, мы можем внести небольшое изменение в синтаксис для добавления строки в конце (с RangeIndex), и теперь типы обрабатываются правильно.
источник