2015-12-21 3 views
5

У меня есть несколько рядов переменных переменной длины с некоторыми нулями. Одним из примеров является:pandas IndexError/TypeError несогласованность с значениями NaN

In [108]: s0 = pd.Series([['a', 'b'],['c'],np.nan]) 
In [109]: s0 
Out[109]: 
0 [a, b] 
1  [c] 
2  NaN 
dtype: object 

а другой содержит все NaNs:

In [110]: s1 = pd.Series([np.nan,np.nan]) 
In [111]: s1 
Out[111]: 
0 NaN 
1 NaN 
dtype: float64 

мне нужен последний элемент в каждом списке, который является простым:

In [112]: s0.map(lambda x: x[-1] if isinstance(x,list) else x) 
Out[112]: 
0  b 
1  c 
2 NaN 
dtype: object 

Но в то время как добраться до этого я обнаружили, что без isinstance, когда индексные дроссели на NaNsделают это по-разному на s0 и s1:

In [113]: s0.map(lambda x: x[-1]) 
... 
TypeError: 'float' object is not subscriptable 

In [114]: s1.map(lamda x: x[-1]) 
... 
IndexError: invalid index to scalar variable. 

Может кто-нибудь объяснить, почему? Это ошибка? Я использую Pandas 0.16.2 и Python 3.4.3.

+0

Интересный вопрос. Это связано с тем, как работает 'pd.Series', поскольку попытка реплицировать это с помощью' list' и 'np.array' приводит к появлению только' TypeError'. – DeepSpace

+0

Пробовали ли вы кортежи, а не списки? По моему опыту кортежи в кадрах данных работают намного лучше. Не уверен, что это касается вашей проблемы, поскольку я не пытался воссоздать –

ответ

1

По сути, это действительно проблема NumPy, а не проблема панд.

map выполняет итерацию над значениями в столбце, чтобы передать их функции lambda по одному за раз. Внизу столбцы/ряды в пандах - это просто (ломтики) массивов NumPy, поэтому pandas определяет следующее helper function, чтобы получить значение из базового массива для функции. Это вызывается map на каждой итерации:

PANDAS_INLINE PyObject* 
get_value_1d(PyArrayObject* ap, Py_ssize_t i) { 
    char *item = (char *) PyArray_DATA(ap) + i * PyArray_STRIDE(ap, 0); 
    return PyArray_Scalar(item, PyArray_DESCR(ap), (PyObject*) ap); 
} 

Ключевой бит PyArray_Scalar, который является функцией API NumPy, который копирует часть массива NumPy из возвращать скалярное значение.

Код, который составляет эту функцию, слишком длинный, чтобы публиковать здесь, но here's где его найти в кодовой базе. Все, что нам нужно знать, это то, что скаляр, который он возвращает, будет соответствовать dtype используемого массива.

Назад к вашей Серии: s0 имеет object DTYPE в то время как s1 имеет float64 DTYPE. Это означает, что PyArray_Scalar вернет другой тип скаляра для каждой серии; фактический Pythonfloat объект и NumPy скалярное поплавок объект соответственно:

>>> type(s0[2]) 
float 
>>> type(s1[0]) 
numpy.float64 

В NaN значения возвращаются в виде двух разных типов, следовательно, различные ошибки при попытке проиндексировать в них с помощью функции lambda.

+0

Большое спасибо, очень ясно! – majr

Смежные вопросы