pandas中的IndexError/TypeError与NaN值不一致性问题

5

我有几个长度不同且包含一些空值的列表系列。以下是一个例子:

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时,s0s1的故障表现不同

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.

有人能解释一下为什么吗?这是个bug吗?我正在使用Pandas 0.16.2和Python 3.4.3。


有趣的问题。这与 pd.Series 的工作方式有关,因为尝试使用 listnp.array 复制它只会导致 TypeError - DeepSpace
你尝试过使用元组而不是列表吗?在我的经验中,数据框架中的元组效果要好得多。不确定这是否解决了你的问题,因为我没有尝试重新创建。 - Woody Pride
1个回答

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);
}

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

构成该函数的代码太长,无法在此处发布,但这里是在代码库中找到它的位置。我们只需要知道它返回的标量将与其使用的数组的dtype匹配即可。

回到你的Series:s0具有object dtype,而s1具有float64 dtype。这意味着PyArray_Scalar将为每个Series返回不同类型的标量;一个实际的Pythonfloat对象和一个NumPy标量浮点对象:

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

“NaN”值返回两种不同的类型,因此当您尝试使用“lambda”函数索引它们时会出现不同的错误。请注意,此处保留HTML标签。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接