pandas IndexError/TypeError与NaN值不一致

maj*_*ajr 5 python indexing exception nan pandas

我有几个可变长度列表和一些空值.一个例子是:

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

但另一个包含所有NaNs:

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

我需要每个列表中的最后一项,这很简单:

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

但是在达到这个目的的过程中,我发现,如果没有它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.
Run Code Online (Sandbox Code Playgroud)

有谁能解释为什么?这是一个错误吗?我正在使用Pandas 0.16.2和Python 3.4.3.

Ale*_*ley 1

从本质上讲,这实际上是一个 NumPy 问题,而不是 pandas 问题。

map迭代列中的值,lambda一次将它们传递给函数。在下面,pandas 中的列/系列只是 NumPy 数组(的切片),因此 pandas 定义了以下辅助函数来从该函数的底层数组中获取值。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);
}
Run Code Online (Sandbox Code Playgroud)

关键位是PyArray_Scalar,它是一个 NumPy API 函数,用于复制 NumPy 数组的一部分以返回标量值。

组成该函数的代码太长,无法在此处发布,但可以 在代码库中找到它。我们需要知道的是它返回的标量将与其所使用的数组的数据类型相匹配。

回到您的系列:s0具有objectdtype,同时s1具有float64dtype。这意味着PyArray_Scalar将为每个系列返回不同类型的标量;分别是一个实际的Python float对象和一个 NumPy 标量浮点对象:

>>> type(s0[2])
float
>>> type(s1[0])
numpy.float64
Run Code Online (Sandbox Code Playgroud)

这些NaN值以两种不同的类型返回,因此当您尝试使用该lambda函数对它们进行索引时会出现不同的错误。