Python NaN上带掩码的数据帧的加权平均值';s

Python NaN上带掩码的数据帧的加权平均值';s,python,pandas,numpy,dataframe,Python,Pandas,Numpy,Dataframe,我已经找到了一些关于平均数据帧的答案,但没有一个包括权重的处理。我已经想出了一个方法来达到我想要的结果(见标题),但我想知道是否有更直接的方法来实现同样的目标 编辑:我需要平均两个以上的数据帧,但是下面的示例代码只包括其中两个 将熊猫作为pd导入 将numpy作为np导入 df1=pd.DataFrame([[np.nan,2,np.nan,0], [3,4,np.nan,1], [np.nan,np.nan,np.nan,5], [np.nan,3,np.nan,4]], 列=列表('ABCD

我已经找到了一些关于平均数据帧的答案,但没有一个包括权重的处理。我已经想出了一个方法来达到我想要的结果(见标题),但我想知道是否有更直接的方法来实现同样的目标

编辑:我需要平均两个以上的数据帧,但是下面的示例代码只包括其中两个

将熊猫作为pd导入
将numpy作为np导入
df1=pd.DataFrame([[np.nan,2,np.nan,0],
[3,4,np.nan,1],
[np.nan,np.nan,np.nan,5],
[np.nan,3,np.nan,4]],
列=列表('ABCD'))
df2=pd.DataFrame([[3,1,np.nan,1],
[2,5,np.nan,3],
[np.nan,4,np.nan,2],
[np.nan,2,1,5]],
列=列表('ABCD'))
我所做的是:

  • 将每个数据帧转换为数组(行),将所有这样转换的数据帧放入一个数组:
来自DFTOARYSTACK(df)的def

对于范围内的i(len(df)):
arrayRow=df.iloc[i]。值
如果i==0:
ArrayStack=arrayRow
其他:
ArrayStack=np.vstack((ArrayStack,arrayRow))
返回阵列堆栈
ArrayStack1=来自DFTOARYSTACK(df1)
ArrayStack2=来自DFTOARYSTACK(df2)
arrayOfArrays=np.array([ArrayStack1,ArrayStack2])
  • 在NAN上应用遮罩并取平均值:
masked=np.ma.masked_数组(ArrayOfarray,
np.isnan(阵列法拉利))
arrayAve=np.ma.平均值(屏蔽,
轴=0,
权重=[1,2])
  • 转换回数据帧,同时将NAN放回:
pd.DataFrame(np.row\u堆栈(arrayAve.filled(np.nan)))
0           1           2   3
0.3.000000 1.333333 NaN 0.666667
1 2.333333 4.666667南2.333333
2南4.000000南3.000000
3南2.333333 1.0 4.666667

正如我所说,这是可行的,但希望有一种更简洁的方法来做到这一点,一行吗?

这对你有用吗?它不是一行,但还是短得多:)

编辑:由于指出速度是一个问题,我在下面提供了优化版本和一些性能结果。在优化版本中,我将数据帧转换为numpy阵列,因为它在那里工作得更快(在您的示例中也是如此):

计时结果:

  • 您的:
    1.18ms±27.5µs/圈(平均±标准偏差7次,每个循环1000次)
  • 我的新版本:
    18.4µs±1.45µs/循环(平均±标准偏差7次,每个循环10000次)
  • 我的旧版本比你的差大约8.5毫秒

为了使这一行整洁,我在进口方面做了一些欺骗,但以下是我能做的最好的:

import pandas as pd
import numpy as np
from numpy.ma import average as avg
from numpy.ma import masked_array as ma

df1 = pd.DataFrame([[np.nan, 2, np.nan, 0],
                    [3, 4, np.nan, 1],
                    [np.nan, np.nan, np.nan, 5],
                    [np.nan, 3, np.nan, 4]],
                   columns=list('ABCD'))

df2 = pd.DataFrame([[3, 1, np.nan, 1],
                    [2, 5, np.nan, 3],
                    [np.nan, 4, np.nan, 2],
                    [np.nan, 2, 1, 5]],
                   columns=list('ABCD'))

df1.combine(df2, lambda x, y: avg([ma(x, np.isnan(x)), ma(y, np.isnan(y))], 0, [1, 2]))
编辑:


我添加了另一种方法,但您可以通过将
arrayOfArrays
定义为
np.array([df1.values,df2.values])
来显著缩短自己的方法。我编辑了我的解决方案以解决性能问题。稍微细微差别的替代方案是
pd.DataFrame(avg([ma(df1.values,np.isnan(df1.values))、ma(df2.values,np.isnan))(df2.values))],0,[1,2])
。但是,这种方法将重新为列编制索引。我忘了提到,我有多个要平均的数据帧(我在示例中包括了两个数据帧,以简化操作,但只是编辑了问题以包含此细节)。我猜最后一个组合不能处理>2个数据帧。你是正确的,它不能处理两个以上的数据帧。我已经用一个处理多个数据帧的函数更新了我的答案。它仍然算作一个线性函数吗?你刚刚让我意识到一个线性函数可能非常难看,但我仍然认为使用
df.values
是不可取的e代码长度方面的改进两点:我想知道你的解决方案在速度方面与我的相比如何(尽管我要求代码“更短”,所以你的答案很重要!)。因为我要平均的数据帧不止2个(编辑问题),应在输入数据帧的末尾添加一个循环,以替换nansI已编辑我的解决方案以解决您的性能问题
import pandas as pd
import numpy as np
df3 = pd.DataFrame([[np.nan, 2, np.nan, 0],
[3, 4, np.nan, 1],
[np.nan, np.nan, np.nan, 5],
[np.nan, 3, np.nan, 4]],
columns=list('ABCD'))

df4 = pd.DataFrame([[3, 1, np.nan, 1],
[2, 5, np.nan, 3],
[np.nan, 4, np.nan, 2],
[np.nan, 2, 1, 5]],
columns=list('ABCD'))

weights = np.array([1,2])
df3 = df3.values
df4 = df4.values

average = (df3*weights[0]+df4*weights[1])/np.sum(weights)
np.copyto(average,df4,where=np.isnan(df3))
np.copyto(average,df3,where=np.isnan(df4))
average
import pandas as pd
import numpy as np
from numpy.ma import average as avg
from numpy.ma import masked_array as ma

df1 = pd.DataFrame([[np.nan, 2, np.nan, 0],
                    [3, 4, np.nan, 1],
                    [np.nan, np.nan, np.nan, 5],
                    [np.nan, 3, np.nan, 4]],
                   columns=list('ABCD'))

df2 = pd.DataFrame([[3, 1, np.nan, 1],
                    [2, 5, np.nan, 3],
                    [np.nan, 4, np.nan, 2],
                    [np.nan, 2, 1, 5]],
                   columns=list('ABCD'))

df1.combine(df2, lambda x, y: avg([ma(x, np.isnan(x)), ma(y, np.isnan(y))], 0, [1, 2]))
import pandas as pd
import numpy as np
from numpy.ma import average as avg
from numpy.ma import masked_array as ma

df1 = pd.DataFrame([[np.nan, 2, np.nan, 0],
                    [3, 4, np.nan, 1],
                    [np.nan, np.nan, np.nan, 5],
                    [np.nan, 3, np.nan, 4]],
                   columns=list('ABCD'))

df2 = pd.DataFrame([[3, 1, np.nan, 1],
                    [2, 5, np.nan, 3],
                    [np.nan, 4, np.nan, 2],
                    [np.nan, 2, 1, 5]],
                   columns=list('ABCD'))

def df_average(dfs, wgts):
      return pd.DataFrame(avg([ma(df.values, np.isnan(df.values)) for df in dfs], 0, wgts))


df_average(dfs=[df1, df2], wgts=[1, 2])