Почему pandas использует «NaN» из numpy вместо собственного нулевого значения? - PullRequest
3 голосов
/ 20 июня 2020

Это что-то вроде c, но я постараюсь сократить его до некоторых конкретных c вопросов.

Начиная отвечать на вопросы по SO, я обнаружил, что иногда сталкиваюсь с такая глупая ошибка при создании игрушечных данных:

In[0]:

import pandas as pd

df = pd.DataFrame({"values":[1,2,3,4,5,6,7,8,9]})
df[df < 5] = np.nan

Out[0]:
NameError: name 'np' is not defined

Я настолько привык автоматически импортировать numpy с pandas, что обычно этого не происходит в реальном коде. Однако это заставило меня задуматься, почему pandas не имеет собственного значения / объекта для представления нулевых значений.

Я только недавно понял, что вы можете просто использовать Python None вместо аналогичная ситуация:

import pandas as pd

df = pd.DataFrame({"values":[1,2,3,4,5,6,7,8,9]})
df[df < 5] = None

Что работает должным образом и не вызывает ошибок. Но я чувствовал, что соглашение о SO, которое я видел, заключается в использовании np.nan, и что люди обычно ссылаются на np.nan при обсуждении нулевых значений (возможно, поэтому я не понял, что None можно использовать , но, возможно, это была моя собственная идиосинкразия).

Кратко рассмотрев это, я теперь увидел, что pandas действительно имеет значение pandas.NA с 1.0.0, но Я никогда не видел, чтобы кто-нибудь использовал его в сообщениях :

In[0]:

import pandas as pd
import numpy as np

df = pd.DataFrame({'values':np.random.rand(20,)})
df['above'] = df['values']
df['below'] = df['values']
df['above'][df['values']>0.7] = np.nan
df['below'][df['values']<0.3] = pd.NA

df['names'] = ['a','b','c','a','b','c','a','b','c','a']*2
df.loc[df['names']=='a','names'] = pd.NA
df.loc[df['names']=='b','names'] = np.nan
df.loc[df['names']=='c','names'] = None
df

Out[0]:
      values     above     below names
0   0.323531  0.323531  0.323531  <NA>
1   0.690383  0.690383  0.690383   NaN
2   0.692371  0.692371  0.692371  None
3   0.259712  0.259712       NaN  <NA>
4   0.473505  0.473505  0.473505   NaN
5   0.907751       NaN  0.907751  None
6   0.642596  0.642596  0.642596  <NA>
7   0.229420  0.229420       NaN   NaN
8   0.576324  0.576324  0.576324  None
9   0.823715       NaN  0.823715  <NA>
10  0.210176  0.210176       NaN  <NA>
11  0.629563  0.629563  0.629563   NaN
12  0.481969  0.481969  0.481969  None
13  0.400318  0.400318  0.400318  <NA>
14  0.582735  0.582735  0.582735   NaN
15  0.743162       NaN  0.743162  None
16  0.134903  0.134903       NaN  <NA>
17  0.386366  0.386366  0.386366   NaN
18  0.313160  0.313160  0.313160  None
19  0.695956  0.695956  0.695956  <NA>

Кажется, что для числовых значений различие между этими разными нулевыми значениями не имеет значения, но они представлены по-разному для строки (и, возможно, для других типов данных?).

Мои вопросы, основанные на приведенном выше :

  • Принято ли использовать np.nan (вместо None) для представления нулевых значений в pandas?
  • Почему pandas не имело собственного нулевого значения большую часть своего существования (до прошлого года)? Что было мотивацией для добавления?
  • В случаях, когда вы можете иметь несколько типов пропущенных значений в одном Series или столбце, есть ли между ними разница? Почему они не представлены одинаково (как с числовыми данными)?

Я полностью предвижу, что у меня может быть неправильная интерпретация вещей и различие между pandas и numpy, поэтому, пожалуйста, поправьте меня .

Ответы [ 3 ]

3 голосов
/ 20 июня 2020

Основная зависимость pandas - это numpy, другими словами, pandas построена поверх numpy. Поскольку pandas наследует и использует многие из методов numpy, имеет смысл сохранять единообразие, то есть отсутствующие данные numeri c представлены как np.NaN.

(Этот выбор для построения on numpy имеет последствия и для других вещей. Например, операции даты и времени построены на типах np.timedelta64 и np.datetime64 dtypes, а не на стандартном модуле datetime.)

Одна вещь, о которой вы, возможно, не знали, это то, что numpy всегда присутствовал с pandas

import pandas as pd
pd.np?
pd.np.nan

Хотя вы могли подумать, что такое поведение могло бы быть лучше, если вы не 't import numpy, это не рекомендуется, и в ближайшем будущем он будет устаревшим в пользу прямого импорта numpy

FutureWarning: модуль pandas .np устарел и будет удален от pandas в будущей версии. Импортируйте numpy напрямую вместо

Принято ли использовать np.nan (вместо None) для представления нулевых значений в pandas?

Если данные числовые c, тогда да, вы должны использовать np.NaN. None требует, чтобы dtype был Object, а с pandas вы хотите, чтобы данные numeri c хранились в numeri c dtype. pandas обычно будет приводить к правильному нулевому типу при создании или импорте, чтобы он мог использовать правильный dtype

pd.Series([1, None])
#0    1.0
#1    NaN        <- None became NaN so it can have dtype: float64
#dtype: float64

Почему pandas не имело собственного нулевого значения большую часть своего существования (до прошлого года)? Что было мотивацией для добавления?

pandas не имело собственного нулевого значения, потому что он обходился с np.NaN, который работал в большинстве случаев. Однако с pandas очень часто отсутствуют данные, поэтому весь раздел документации посвящен этому. NaN, будучи вещественным числом, не помещается в контейнер целых чисел, что означает, что любая серия numeri c с отсутствующими данными преобразуется в float. Это может стать проблемой c из-за математики с плавающей запятой , и некоторые целые числа не могут быть идеально представлены числами с плавающей запятой. В результате любые соединения или merges могут потерпеть неудачу.

# Gets upcast to float
pd.Series([1,2,np.NaN])
#0    1.0
#1    2.0
#2    NaN
#dtype: float64

# Can safely do merges/joins/math because things are still Int
pd.Series([1,2,np.NaN]).astype('Int64')
#0       1
#1       2
#2    <NA>
#dtype: Int64
1 голос
/ 20 июня 2020

Отличный вопрос! Я догадываюсь, что это связано с тем, что NumPy функции реализованы в C, что делает его очень быстрым. Python None может не дать вам такой же эффективности (или, вероятно, переведен в np.nan), в то время как pd.NA Pandas скорее всего будет переведен в NumPy np.nan в любом случае, поскольку Pandas требуется NumPy. Тем не менее, я еще не нашел ресурсов, подтверждающих мои утверждения.

0 голосов
/ 20 июня 2020
  • Во-первых, вы можете объединить значения nan с помощью filter-function, которое возвращает только одно значение, скажем, None.
  • Я думаю, причина в том, чтобы сделать его уникальным в случае данных -майнинг данных из numpy вычислений или так далее. Итак, pandas nan означает нечто иное. Возможно, здесь в вашем частном случае это не имеет смысла, но в других случаях это будет иметь значение.
...