NaN上带掩码的数据帧的加权平均

2024-10-02 00:21:41 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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

import pandas as pd
import numpy as 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]],
                   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 fromDfToArraysStack(df):

    for i in range(len(df)):
         arrayRow = df.iloc[i].values

         if i == 0:
             arraysStack = arrayRow
         else:
             arraysStack = np.vstack((arraysStack, arrayRow))

    return arraysStack

arraysStack1 = fromDfToArraysStack(df1)
arraysStack2 = fromDfToArraysStack(df2)
arrayOfArrays = np.array([arraysStack1, arraysStack2])
  • 在NAN上应用遮罩并取平均值:
masked = np.ma.masked_array(arrayOfArrays,
                            np.isnan(arrayOfArrays))
arrayAve = np.ma.average(masked,
                         axis = 0,
                         weights = [1,2])
  • 转换回数据帧,同时将NAN放回:
pd.DataFrame(np.row_stack(arrayAve.filled(np.nan)))

    0           1           2   3
0   3.000000    1.333333    NaN 0.666667
1   2.333333    4.666667    NaN 2.333333
2   NaN         4.000000    NaN 3.000000
3   NaN         2.333333    1.0 4.666667

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


Tags: 数据方法importdataframedfasnpnan
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'))

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])

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

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 = [1,2]
average = (df3*weights[0]+df4*weights[1])/sum(weights)
average[df3.isna()] = df4
average[df4.isna()] = df3
average

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

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

计时结果:

  • 你的:1.18 ms ± 27.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
  • 我的新:18.4 µs ± 1.45 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  • 我的旧版本比你的差大约8.5毫秒

相关问题 更多 >

    热门问题