Как запретить Pandas DataFrame преобразовывать int в float без причины? - PullRequest
3 голосов
/ 01 апреля 2019

Я создаю небольшой DataFrame Pandas и добавляю в него некоторые данные, которые должны быть целыми числами. Но даже несмотря на то, что я очень стараюсь явно установить dtype в int и предоставлять только значения int, он всегда становится плавающим. Это не имеет никакого смысла для меня вообще, и поведение даже не кажется полностью последовательным.

Рассмотрим следующий скрипт Python:

import pandas as pd

df = pd.DataFrame(columns=["col1", "col2"])  # No dtype specified.
print(df.dtypes)  # dtypes are object, since there is no information yet.
df.loc["row1", :] = int(0)  # Add integer data.
print(df.dtypes)  # Both columns have now become int64, as expected.
df.loc["row2", :] = int(0)  # Add more integer data.
print(df.dtypes)  # Both columns are now float64???
print(df)  # Shows as 0.0.

# Let's try again, but be more specific.
del df  
df = pd.DataFrame(columns=["col1", "col2"], dtype=int)  # Explicit set dtype.
print(df.dtypes)  # For some reason both colums are already float64???
df.loc["row1", :] = int(0)
print(df.dtypes)  # Both colums still float64.

# Output:
"""
col1    object
col2    object
dtype: object
col1    int64
col2    int64
dtype: object
col1    float64
col2    float64
dtype: object
      col1  col2
row1   0.0   0.0
row2   0.0   0.0
col1    float64
col2    float64
dtype: object
col1    float64
col2    float64
dtype: object
"""

Я могу это исправить, выполнив df = df.astype(int) в конце. Есть и другие способы исправить это. Но это не должно быть необходимым. Я пытаюсь выяснить, что я делаю неправильно, что делает колонки плавающими.

Что происходит?

Python версия 3.7.1 Панды версия 0.23.4

EDIT:

Я думаю, может быть, некоторые люди неправильно понимают. В этом DataFrame никогда не бывает значений NaN. Сразу после его создания это выглядит так:

Empty DataFrame
Columns: [col1, col2]
Index: []

Это пустой Dataframe, df.shape = 0, но в нем нет NaN, просто еще нет строк.

Я также обнаружил кое-что еще хуже. Даже если я добавлю df = df.astype(int) после добавления данных так, чтобы они стали целыми, он снова станет плавающим, как только я добавлю больше данных !

df = pd.DataFrame(columns=["col1", "col2"], dtype=int)
df.loc["row1", :] = int(0)
df.loc["row2", :] = int(0)
df = df.astype(int)  # Force it back to int.
print(df.dtypes)  # It is now ints again.
df.loc["row3", :] = int(0)  # Add another integer row.
print(df.dtypes)  # It is now float again???

# Output:
"""
col1    int32
col2    int32
dtype: object
col1    float64
col2    float64
dtype: object
"""

Предлагаемое исправление в версии 0.24 не похоже на мою проблему. Эта особенность относится к типу данных Nullable Integer. В моих данных нет значений NaN или None.

1 Ответ

1 голос
/ 02 апреля 2019

df.loc["rowX"] = int(0) сработает и решит проблему, поставленную в вопросе.df.loc["rowX",:] = int(0) не работает.Это сюрприз.

df.loc["rowX"] = int(0) предоставляет возможность заполнять пустой фрейм данных, сохраняя при этом нужный тип d.Но это можно сделать для всей строки за раз.

df.loc["rowX"] = [np.int64(0), np.int64(1)] работает.

.loc[] подходит для присвоения на основе меток для https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.loc.html. Примечание: 0,24Документ не отображает .loc [] для вставки новых строк.

Документ показывает использование .loc[] для добавления строк путем присваивания чувствительным к столбцу способом.Но делает это, когда DataFrame заполнен данными.

Но это становится странным, когда нарезается пустой кадр.

import pandas as pd
import numpy as np
import sys

print(sys.version)
print(pd.__version__)

print("int dtypes preserved")
# append on populated DataFrame
df = pd.DataFrame([[0, 0], [1,1]], index=['a', 'b'], columns=["col1", "col2"])
df.loc["c"] = np.int64(0)
# slice existing rows
df.loc["a":"c"] = np.int64(1)
df.loc["a":"c", "col1":"col2":1] = np.int64(2)
print(df.dtypes)

# no selection AND no data, remains np.int64 if defined as such
df = pd.DataFrame(columns=["col1", "col2"], dtype=np.int64)
df.loc[:, "col1":"col2":1] = np.int64(0)
df.loc[:,:] = np.int64(0)
print(df.dtypes)

# and works if no index but data
df = pd.DataFrame([[0, 0], [1,1]], columns=["col1", "col2"])
df.loc[:,"col1":"col2":1] = np.int64(0)
print(df.dtypes)

# the surprise... label based insertion for the entire row does not convert to float
df = pd.DataFrame(columns=["col1", "col2"], dtype=np.int64)
df.loc["a"] = np.int64(0)
print(df.dtypes)

# a surprise because referring to all columns, as above, does convert to float
print("unexpectedly converted to float dtypes")
df = pd.DataFrame(columns=["col1", "col2"], dtype=np.int64)
df.loc["a", "col1":"col2"] = np.int64(0)
print(df.dtypes)

3.7.2 (default, Mar 19 2019, 10:33:22) 
[Clang 10.0.0 (clang-1000.11.45.5)]
0.24.2
int dtypes preserved
col1    int64
col2    int64
dtype: object
col1    int64
col2    int64
dtype: object
col1    int64
col2    int64
dtype: object
col1    int64
col2    int64
dtype: object
unexpectedly converted to float dtypes
col1    float64
col2    float64
dtype: object
...