#python-3.x #pandas #dataframe #numpy #types
Вопрос:
когда у меня есть фрейм данных со значениями np.uint64
import pandas as pd
import numpy as np
df = pd.DataFrame(columns=['a','b'])
df.a = [1, 3]
df.b = [1, 3]
df = df.astype({'a': np.uint64, 'b': np.uint64})
print(df.info())
он возвращается
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 2 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 a 2 non-null uint64
1 b 2 non-null uint64
dtypes: uint64(2)
memory usage: 160.0 bytes
None
Когда я сейчас пытаюсь добавить ячейку в фрейм данных:
x = np.uint64(5)
print(type(x))
ВОЗВРАТ
<class 'numpy.uint64'>
и
df.at[2, 'a'] = x
print(type(df.at[2, 'a']))
print(df.dtypes)
ВОЗВРАТ
<class 'numpy.float64'>
<class 'pandas.core.frame.DataFrame'>
Int64Index: 3 entries, 0 to 2
Data columns (total 2 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 a 3 non-null float64
1 b 2 non-null float64
dtypes: float64(2)
memory usage: 180.0 bytes
None
Почему тип столбцов и значений меняется с np.uint64 на float64?
Ответ №1:
Я верю, что это потому, что, когда вы это делаете:
x = np.uint64(5)
df.at[2, 'a'] = x
Он генерирует NaN для столбца B, а pandas не позволяет NaN быть целыми числами, что и делает uint(64).
Если вы добавите строку, в которой нет нулей, и преобразуете фрейм данных обратно в unit64, это позволит:
df = df.astype({'a': np.uint64, 'b': np.uint64})
Если это ответ на ваш вопрос, пожалуйста, отметьте это как решение!
Ответ №2:
Обратите внимание, что numpy uint64
не может быть нулевым, поэтому он автоматически преобразуется в float64
значение после nan
появления.
Однако у панд есть целочисленный тип с dtype=pd.Int64Dtype()
возможностью обнуления (или псевдоним как dtype='Int64'
):
df = pd.DataFrame({'a': [1, 3], 'b': [1, 3]}, dtype='Int64')
# a b
# 0 1 1
# 1 3 3
df.dtypes
# a Int64
# b Int64
# dtype: object
df.loc[2, 'a'] = np.uint64(5)
# a b
# 0 1 1
# 1 3 3
# 2 5 <NA>
df.dtypes
# a Int64
# b Int64
# dtype: object
Комментарии:
1. Спасибо вам за это объяснение! Что заставляет меня задуматься: почему весь dtype фрейма данных изменен на float64? Делает df.at[2, ‘a’] = x сгенерировать/добавить новую строку со значениями NaN перед копированием x в ячейку?
2. @rafa Да, он добавляет новую серию строк, что вызывает цепную реакцию, поскольку серии не могут иметь смешанные типы dtypes (если вы не превратите их в
dtype='object'
). Он не может добавить новую строку как[int,float]
, поэтому он передает строку в[float,float]
. Затем в результатеfloat
в каждый столбец теперь добавляется a, поэтому каждый столбецfloat
также обновляется.3. Спасибо за объяснение!
Ответ №3:
Обновление и следующий вопрос:
Мое решение для решения проблемы:
Вместо того, чтобы использовать np.uint64
значения, в которые я их предварительно привел np.int64
.
df = pd.DataFrame(columns=['a','b'])
df.a = [1, 3]
df.b = [1, 3]
df = df.astype({'a': np.int64, 'b': np.int64})
print(df.dtypes)
# a int64
# b int64
# dtype: object
В случае одного я снова добавляю одно значение:
x = np.int64(5)
print(type(x)) # <class 'numpy.int64'>
df.at[2, 'a'] = x
print(type(df.at[2, 'a'])) # <class 'numpy.float64'>
print(df.dtypes)
# a float64
# b float64
# dtype: object
Опять же, оба столбца приводятся к плавающему значению, потому NaN
что не допускают целых чисел. Верно?
Но в случае второго, когда я вместо этого делаю следующее:
df = pd.DataFrame(columns=['a','b'])
df.a = [1, 3]
df.b = [1, 3]
df = df.astype({'a': np.int64, 'b': np.int64})
print(df.dtypes)
# a int64
# b int64
# dtype: object
df_row = pd.DataFrame(columns=['a','b'])
df_row.a = [5]
df_row.b = [5]
print(df_row.dtypes)
# a int64
# b int64
# dtype: object
df = df.append(df_row, ignore_index=True)
print(df.dtypes)
# a int64
# b int64
# dtype: object
это означает, что при добавлении в этой ситуации фрейм данных не изменяет тип данных.
Но опять же, если сделать то же самое с np.uint64
:
df = pd.DataFrame(columns=['a','b'])
df.a = [1, 3]
df.b = [1, 3]
df = df.astype({'a': np.uint64, 'b': np.uint64})
print(df.dtypes)
# a uint64
# b uint64
# dtype: object
df_row = pd.DataFrame(columns=['a','b'])
df_row.a = [np.uint64(5)]
df_row.b = [np.uint64(5)]
print(df_row.dtypes)
# a int64
# b int64
# dtype: object
df = df.append(df_row, ignore_index=True)
print(df.dtypes)
# a float64
# b float64
# dtype: object
Типы столбцов df_row
объясняет, что позже в append
типах будут изменены на float64
Но почему тип данных в df_row.a = [np.uint64(5)]
изменен на int64
?