【问题标题】:Vectorized calculation of simple statistics for bins of subarrays, separately for fixed-width bins and fixed-frequency bins子阵列箱的简单统计的矢量化计算,分别用于固定宽度箱和固定频率箱
【发布时间】:2022-01-07 08:09:00
【问题描述】:

我有一个子数组数组如下:

[
    [...]
    [...]
      ⋮
    [...]
]

每个子数组的长度相同。
我需要对每个子数组进行分箱并计算每个箱的平均值、标准差、中位数和其他百分位数。我需要按固定宽度和固定频率进行分箱的单独结果。 该方法应该是矢量化的,即没有“for 循环”(或至少尽可能少且成本不会太高,当然每种分箱技术都需要单独的方法)。我不知道这是否可能以一种可以合理理解的方式实现(对我来说可以理解,因为我是个菜鸟,但如果它有效,我会尽力而为)。对于固定宽度的分箱方法,您可以假设我们按第一个子数组的数据范围进行分箱以方便。

我应该如何进行?

可能性:
对于固定频率分箱,我想到的步骤是通过指定右轴参数以某种方式立即执行np.array_split,然后使用np.pad 填充比nan 更短的分箱,现在子阵列没有更长的由参差不齐的序列组成,我们希望能够再次使用适用于np.array_split 的任何轴指定来应用np.nanmedian。但是,我不知道是否可以为拆分和中值操作指定任何合适的此类轴,此外,我已经看到无法避免迭代(不仅是每一行,而是)每个 bin用额外的 nan 填充这些参差不齐的序列中较短的一个。即使这些迭代没有证明成本高昂并且其他一切都很好,我也不知道如何实际实施此过程的任何步骤。我也不知道从哪里开始固定宽度的分箱。

Here is a vectorized solution 仅针对单个数组的均值完成我想要的;我当然想避免遍历我的每个子数组,并且对方法的理解不足以将其扩展到计算标准差、中位数或任何其他百分位数。

如果您建议的方法是通过 pandas 库,例如使用 cut 或 qcut,有没有一种方法可以在不使用 for 循环的情况下完成?

这一切都与my earlier question密切相关。
由于我是这个平台的新手,我不确定最佳实践是什么,理想情况下我不希望删除该帖子,因为它可以覆盖更广泛的网络来解决我的问题,而这篇文章追求的是描述的更具体的途径在那里面。我也不希望曾经为该帖子提供答案的人发现它已被删除。但是,如果很清楚我应该删除之前的帖子,请告诉我。

编辑:具有预期输出的示例,假设所有对象都是 numpy 数组而不是列表
示例数组:

[
    [0, 1, 2, 3, 4, 5, 6],
    [90, 45,  9, 88, 21, 59, 32],
    ⋮
]

每个 bin 分箱示例 3 个对象的固定频率

[
    [[0, 1, 2], [3, 4], [5, 6]],
    [[90, 45,  9], [88, 21], [59, 32]],
    ⋮
]

上述中间步骤无需在任何时候显式返回,而是说明了幕后将发生的情况。

固定频率分箱示例的中位数输出

[
    [1, 3.5, 5.5],
    [45, 54.5, 45.5],
    ⋮
]

编辑 2:使用@hilberts_drinking_problem 答案作为原始问题的可接受解决方案的扩展问题
如果x = [0, 1, 2, 3, 4, 5, 6]y = [90, 45, 9, 88, 21, 59, 32],那么您已经计算了我想要的按x 排序的数据的所有内容(百分位数除外)。如果我也想要相同的统计信息,但数据按 y 排序并使用多索引,这样 df_2 的行索引打印如下:

# x_srtd   x  
#          y  
# y_srtd   x  
#          y  

如果没有 for 循环,我将如何获得这个(包括再次按 y 对 x 和 y 进行排序)。 (如果重要的话,我计划在最后使用.T 转置整个 df_2,以提高可读性,例如“x_srtd”、“y_srtd”、“x”和“y”成为列标题。
还有你会推荐Pass percentiles to pandas agg function 中的哪些方法?
几乎忘记了,关于如何处理固定宽度分箱的任何想法,记住 x 排序的分箱将与 y 排序的分箱不同。例如,以 bin_width_x = 1.5 为 x 分箱,bin_width_y = 25 类似。

【问题讨论】:

标签: python pandas numpy vectorization


【解决方案1】:

您可以将 DataFrame 的列拆分为 MultiIndex,以便多索引的第零级表示您希望聚合的一组列。这是一个例子:

import pandas as pd
import numpy as np

df = pd.DataFrame([
    [0, 1, 2, 3, 4, 5, 6],
    [90, 45,  9, 88, 21, 59, 32],
])

df.columns = pd.MultiIndex.from_tuples(
    [(i, c) for i, gp in enumerate(np.array_split(df.columns, 3)) for c in gp]
)
# print(df)
#     0          1       2    
#     0   1  2   3   4   5   6
# 0   0   1  2   3   4   5   6
# 1  90  45  9  88  21  59  32

print(df.groupby(axis=1, level=0).agg("mean"))
#       0     1     2
# 0   1.0   3.5   5.5
# 1  48.0  54.5  45.5

# the following raises not implemented error on Pandas version 1.1.5
# print(df.groupby(axis=1, level=0).agg(["mean", "std"]))

# as a workaround:
operations = ["mean", "std", "median"]
df2 = pd.concat((
    df.groupby(axis=1, level=0).agg(operation)
    for operation in operations
), axis=1)
df2.columns = pd.MultiIndex.from_product([
  operations, np.unique(df.columns.get_level_values(0))])
print(df2)
#    mean                    std                       median            
#       0     1     2          0          1          2      0     1     2
# 0   1.0   3.5   5.5   1.000000   0.707107   0.707107    1.0   3.5   5.5
# 1  48.0  54.5  45.5  40.583248  47.376154  19.091883   45.0  54.5  45.5

【讨论】:

  • 哇,你简洁的 pandas 操作令人印象深刻,但不幸的是,由于代表我不能投票给你。既然你知道你的东西,我想就如何管理我的数据请求更多建议。我已经发布了对原始问题的编辑 2,很想听听您的想法。
猜你喜欢
  • 1970-01-01
  • 2017-01-09
  • 1970-01-01
  • 2011-12-22
  • 2015-12-27
  • 2017-01-25
  • 2021-08-29
  • 1970-01-01
  • 2022-10-08
相关资源
最近更新 更多