Делая Int64 по умолчанию целочисленный тип dtype вместо стандартного int64 в пандах

Мне бы хотелось, чтобы все мои фреймы данных, независимо от того, созданы ли они из-за какой-либо из перегрузок конструктора, получены ли они из .read_csv(), .read_xlsx(), .read_sql() или любого другого метода, чтобы использовать новый обнуляемый Int64 тип данных в качестве значения по умолчанию dtype для всех целых чисел, а не int64.

Я готов пойти буквально на любой уровень безумия, чтобы сделать это, если нет "хорошего" способа, включая создание подклассов классов DataFrame или Series, а также переопределение любого количества методов и атрибутов конструктора и т.д.

У меня вопрос: можно ли это сделать? Если да, то как мне это сделать?

Ответ 1

Вы можете использовать такую функцию:

def nan_ints(df,convert_strings=False,subset = None):
    types = ['int64','float64']
    if subset is None:
        subset = list(df)
    if convert_strings:
        types.append('object')
    for col in subset:
        try:
            if df[col].dtype in types:
                df[col] = df[col].astype(float).astype('Int64')
        except:
            pass
    return df

Он перебирает каждый столбец и закрывает его до Int64, если это int. Если это число с плавающей точкой, оно будет преобразовано в Int64, только если все значения в столбце могут быть преобразованы в целые числа, отличные от NaN. Я также дал вам возможность конвертировать строки в Int64 с помощью аргумента convert_strings.

df1 = pd.DataFrame({'a':[1.1,2,3,1],
                  'b':[1,2,3,np.nan],
                  'c':['1','2','3',np.nan],
                  'd':[3,2,1,np.nan]})


nan_ints(df1,convert_strings=True,subset=['b','c'])
df1.info()

Вернет следующее:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 4 columns):
a    4 non-null float64
b    3 non-null Int64
c    3 non-null Int64
d    3 non-null float64
dtypes: Int64(2), float64(2)
memory usage: 216.0 bytes

если вы собираетесь использовать это в каждом DataFrame, вы можете добавить функцию в модуль и импортировать ее каждый раз, когда захотите использовать панд. from my_module import nan_ints Тогда просто используйте это с чем-то вроде: nan_ints(pd.read_csv(path))

Примечание. Целочисленный тип данных Nullable - Новый в версии 0.24.0. Вот документация.

Ответ 2

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

import pandas
pandas.DataFrame.__old__init__ = pandas.DataFrame.__init__
def new_init(self, data=None, index=None, columns=None, dtype=pd.Int64Dtype(), copy=False):
    self.__old__init__(data=data, index=index, columns=None, dtype=dtype, copy=copy)

pandas.DataFrame.__init__ = new_init

Конечно, вы рискуете разрушить мир. Удачи!