在pandas数据帧上使用apply时传递的值的形状错误

Dji*_*ggy 1 python apply dataframe pandas

我试图在给定数据帧的所有行(dfTest,其中包含向量x的值)上应用基本样条函数,以获得更大的一个(dfBigger),它将包含向量xnew(包含x)的所有值.

因此,我定义了以下变量:

import pandas as pd
import numpy as np

x = [0,1,3,5]
xnew = range(0,6)

np.random.seed(123)
dfTest = pd.DataFrame(np.random.rand(12).reshape(3,4))
Run Code Online (Sandbox Code Playgroud)

和基本样条函数:

def spline(y, x , xnew):
    from scipy import interpolate
    model = interpolate.splrep(x,y, s=0.)
    ynew = interpolate.splev(xnew,model)
    result = ynew.round(3)
    return result
Run Code Online (Sandbox Code Playgroud)

这似乎工作:

spline(dfTest.iloc[0],x,xnew)
Out[176]: array([ 0.696,  0.286,  0.161,  0.227,  0.388,  0.551])
Run Code Online (Sandbox Code Playgroud)

但是当我尝试使用以下方法在所有行上应用它时:

dfBigger = dfTest.apply(lambda row : spline(row, x, xnew), axis = 1)
Run Code Online (Sandbox Code Playgroud)

我懂了 :

ValueError: Shape of passed values is (3, 6), indices imply (3, 4)
Run Code Online (Sandbox Code Playgroud)

由于dfBigger大小没有在任何地方定义,我看不出有什么问题.任何有关此代码的帮助和/或评论将不胜感激.

unu*_*tbu 6

df.apply(func)尝试从返回的值中构建新的Series或DataFrame func.Series或DataFrame的形状取决于返回的值的类型func.为了更好地处理df.apply行为方式,请尝试以下调用:

dfTest.apply(lambda row: 1, axis=1)                       # Series
dfTest.apply(lambda row: [1], axis=1)                     # Series
dfTest.apply(lambda row: [1,2], axis=1)                   # Series
dfTest.apply(lambda row: [1,2,3], axis=1)                 # Series
dfTest.apply(lambda row: [1,2,3,4], axis=1)               # Series
dfTest.apply(lambda row: [1,2,3,4,5], axis=1)             # Series

dfTest.apply(lambda row: np.array([1]), axis=1)           # DataFrame
dfTest.apply(lambda row: np.array([1,2]), axis=1)         # ValueError
dfTest.apply(lambda row: np.array([1,2,3]), axis=1)       # ValueError
dfTest.apply(lambda row: np.array([1,2,3,4]), axis=1)     # DataFrame!
dfTest.apply(lambda row: np.array([1,2,3,4,5]), axis=1)   # ValueError

dfTest.apply(lambda row: pd.Series([1]), axis=1)          # DataFrame
dfTest.apply(lambda row: pd.Series([1,2]), axis=1)        # DataFrame
dfTest.apply(lambda row: pd.Series([1,2,3]), axis=1)      # DataFrame
dfTest.apply(lambda row: pd.Series([1,2,3,4]), axis=1)    # DataFrame
dfTest.apply(lambda row: pd.Series([1,2,3,4,5]), axis=1)  # DataFrame
Run Code Online (Sandbox Code Playgroud)

那么我们可以从这些实验中得出什么规则?

  • 如果func返回标量或列表,则df.apply(func)返回一个Series.
  • 如果func返回Series,则df.apply(func)返回DataFrame.
  • 如果func返回1D NumPy数组,并且数组只有一个元素,则df.apply(func)返回DataFrame.(不是一个非常有用的案例......)
  • 如果func返回1D NumPy数组,并且数组具有与df列相同数量的元素,则df.apply(func)返回DataFrame.(有用,但有限)

由于func返回6个值,并且您希望将DataFrame作为结果,因此解决方案是func返回Series而不是NumPy数组:

def spline(y, x, xnew):
    ...
    return pd.Series(result)
Run Code Online (Sandbox Code Playgroud)
import numpy as np
import pandas as pd
from scipy import interpolate

def spline(y, x, xnew):
    model = interpolate.splrep(x,y, s=0.)
    ynew = interpolate.splev(xnew,model)
    result = ynew.round(3)
    return pd.Series(result)

x = [0,1,3,5]
xnew = range(0,6)
np.random.seed(123)
dfTest = pd.DataFrame(np.random.rand(12).reshape(3,4))
# spline(dfTest.iloc[0],x,xnew)
dfBigger = dfTest.apply(lambda row : spline(row, x, xnew), axis=1)
print(dfBigger)
Run Code Online (Sandbox Code Playgroud)

产量

        0      1      2      3      4      5
 0  0.696  0.286  0.161  0.227  0.388  0.551
 1  0.719  0.423  0.630  0.981  1.119  0.685
 2  0.481  0.392  0.333  0.343  0.462  0.729
Run Code Online (Sandbox Code Playgroud)