在Pandas DataFrame.apply

时间:2017-01-11 17:57:24

标签: python pandas dataframe

我正在尝试apply DataFrames个行中的函数(使用applyaxis=1)。该函数返回具有2维的NDArray。我希望将apply返回到恰好包含2D NDArrays的单个对象列,但我得到:

<venv>/lib/python2.7/site-packages/pandas/core/frame.pyc in _homogenize(data, index, dtype)
   5544                 v = lib.fast_multiget(v, oindex.values, default=NA)
   5545             v = _sanitize_array(v, index, dtype=dtype, copy=False,
-> 5546                                 raise_cast_failure=False)
   5547 
   5548         homogenized.append(v)

<venv>/lib/python2.7/site-packages/pandas/core/series.pyc in _sanitize_array(data, index, dtype, copy, raise_cast_failure)
   2918     elif subarr.ndim > 1:
   2919         if isinstance(data, np.ndarray):
-> 2920             raise Exception('Data must be 1-dimensional')
   2921         else:
   2922             subarr = _asarray_tuplesafe(data, dtype=dtype)

Exception: Data must be 1-dimensional

有没有办法告诉Pandas不要试图解开阵列?

更新示例:

arr = np.ones((3,3))
pd.DataFrame({'d': [arr, arr]}).apply(lambda x: x.ix['d'], axis=1)

1 个答案:

答案 0 :(得分:0)

在一个系列上运行apply并用多维对象填充它可以正常工作

pd.Series([1, 2]).apply(lambda x: np.array([[x, x], [x, x]]))

0    [[1, 1], [1, 1]]
1    [[2, 2], [2, 2]]
dtype: object

但是,在数据帧上,pandas期望返回值为标量或一维

考虑数据框df

df = pd.DataFrame([[1, 2]])

这有效

df.apply(lambda x: 1)

0    1
1    1
dtype: int64

这个

df.apply(lambda x: [1])

   0  1
0  1  1

这个

df.apply(lambda x: [1] * 2)

0    [1, 1]
1    [1, 1]
dtype: object

请注意,当我们返回一个长度为1的列表时,它返回了一个数据帧,但是当我们返回一个长度大于1的列表时,它又恢复为一系列列表。

<强> HOLDON!
让我们加倍df

的长度
df = pd.DataFrame([[1, 2]] * 2)

并运行同样的事情

df.apply(lambda x: [1] * 2)

   0  1
0  0  0
1  0  0

哇!好吧,所以我在两个不同的数据帧上运行相同的东西。看起来当返回值的长度与数据帧的off维度匹配时,pandas假定将返回值与off维度索引匹配。

我们可以用pd.Series覆盖它,其中pandas将放弃其解释并使用它给出的系列索引。

df.apply(lambda x: pd.Series([1] * 5))

   0  1
0  1  1
1  1  1
2  1  1
3  1  1
4  1  1

那么ndarray

这打破了

df.apply(lambda x: np.ones((3, 2)))
Exception: Data must be 1-dimensional

这可行,但不是你想要的

df.apply(lambda x: np.ones((3, 2)).tolist())

0    [[1.0, 1.0], [1.0, 1.0], [1.0, 1.0]]
1    [[1.0, 1.0], [1.0, 1.0], [1.0, 1.0]]
dtype: object

解决方案

相反,我会使用传递的索引

来说明pd.Series的理解
f = lambda x: np.ones((3, 2))

pd.Series([f(c) for _, c in df.iteritems()], df.columns)

0    [[1.0, 1.0], [1.0, 1.0], [1.0, 1.0]]
1    [[1.0, 1.0], [1.0, 1.0], [1.0, 1.0]]
dtype: object

注意:

type(pd.Series([f(c) for _, c in df.iteritems()], df.columns).iloc[0])

numpy.ndarray