gpt4 book ai didi

python - 在Python/Pandas中创建部分SAS PROC Summary替换

转载 作者:太空狗 更新时间:2023-10-29 20:28:22 27 4
gpt4 key购买 nike

我们正在努力脱离SAS,转而使用Python/Pandas。但是,我们遇到的一件事是创建具有SAS例程灵活性的PROC SUMMARY(AKA PROC MEANS)的替代品。对于非SAS用户:PROC SUMMARY只是一个例程,该例程会生成一个表,该表包含数据集中“所有观察值或一组观察值内变量的描述性统计信息”,以解释SAS文档。我们的需求只是全部功能的一小部分-输出一个我们拥有的表:

  • 能够将不同的统计信息应用于不同的列(现在仅计算,求和,平均值,加权平均值)
  • 能够处理零到许多分组变量
  • 能够为加权均值
  • 指定权重变量

    我们没有尝试做其他任何事情(任何图形等)。

    到目前为止,这是我们所拥有的:
    def wmean_ungrouped (d,w):
    return (d.dot(w)).sum() / w.sum()

    def wmean_grouped (group, var_name_in, var_name_weight):
    d = group[var_name_in]
    w = group[var_name_weight]
    return (d * w).sum() / w.sum()

    FUNCS = {
    "mean" : np.mean ,
    "sum" : np.sum ,
    "count" : np.count_nonzero
    }

    def my_summary (
    data ,
    var_names_in ,
    var_names_out ,
    var_functions ,
    var_name_weight = None ,
    var_names_group = None
    ):
    result = DataFrame()

    if var_names_group is not None:
    grouped = data.groupby (var_names_group)
    for var_name_in, var_name_out, var_function in \
    zip(var_names_in,var_names_out,var_functions):
    if var_function == "wmean":
    func = lambda x : wmean_grouped (x, var_name_in, var_name_weight)
    result[var_name_out] = Series(grouped.apply(func))
    else:
    func = FUNCS[var_function]
    result[var_name_out] = grouped[var_name_in].apply(func)
    else:
    for var_name_in, var_name_out, var_function in \
    zip(var_names_in,var_names_out,var_functions):
    if var_function == "wmean":
    result[var_name_out] = \
    Series(wmean_ungrouped(data[var_name_in], data[var_name_weight]))
    else:
    func = FUNCS[var_function]
    result[var_name_out] = Series(func(data[var_name_in]))

    return result

    这是对 my_summary()函数的示例调用:
        my_summary (
    data=df,
    var_names_in=["x_1","x_1","x_1","x_1"] ,
    var_names_out=[
    "x_1_c","x_1_s","x_1_m","x_1_wm"
    ] ,
    var_functions=["count","sum","mean","wmean"] ,
    var_name_weight="val_1" ,
    var_names_group=["Region","Category"]
    )
    my_summary()可以工作,但是如您所见,它的实现不是最漂亮的。以下是主要问题:
  • 取决于分组的或未分组的,有两种不同的代码路径-这完全​​源于DataFrameDataFrameGroupBy具有将程序选择的归约函数应用于单列的不同方法。对于DataFrame,我发现的唯一方法是直接调用func(data[var_name_in])data[var_name_in].apply(func)不起作用,因为apply()上的Series不会减少(与apply()上的DataFrame不同)。另一方面,对于DataFrameGroupBy,我必须使用这种方法:grouped[var_name_in].apply(func)。那是因为像func(grouped[var_name_in])这样的东西不起作用(没有理由应该这样做)。
  • 加权均值的特殊处理-这是因为它在两列上进行运算,而与所有其他计算不同,后者仅对一列进行运算;我不知道这是否可以帮助您。
  • 两种不同的加权均值函数-这是第一个问题的结果。未分组的函数具有Series类型的参数,需要dot()对其进行乘减。分组的函数最终会处理SeriesGroupBy对象,并且必须使用*运算符(对于加权平均函数代码,对the answer to this SO post的确认。)

  • 所以我的问题是:
  • Pandas 是否有某种东西可以完成所有这些工作(即扔掉上面的东西并改用它)?
  • 如果不是,是否对上述任何问题进行了修复?
  • 碰巧有什么办法可以不进行分组-即从DataFrameGroupBy获取DataFrame对象而不对任何变量进行分组吗?然后,将减少代码路径,因为我们将专门处理DataFrameGroupBy接口(interface)。

  • 更新(旧-向下滚动至当前)

    @JohnE的答案提供了一种按任何内容进行分组的方法: groupby(lambda x: True)。这是他发现 in this SO post的一种解决方法(顺便说一句,Wes本人回答说需要 DataFrame.agg(),这将达到相同的目的)。 @JohnE的出色解决方案使我们可以专门处理 DataFrameGroupBy类型的对象,并立即减少大多数代码路径。由于我们只有 DataFrameGroupBy实例,因此我可以使用一些可能的功能来进一步减少麻烦。基本上,所有函数都是根据需要生成的-“生成器”(在此处加引号,以免与Python生成器表达式混淆)采用两个参数:值列名称和权重列名称,在所有情况下都将忽略其中的第二个参数 wmean。生成的函数始终应用在整个 DataFrameGroupBy上,就像最初使用 wmean一样,其参数是要使用的正确列名。我还用 Pandas 计算替换了所有的 np.*实现,以便更好地处理 NaN值。

    除非有 Pandas 原生的东西可以做到这一点,否则这是我们的解决方案:
    FUNC_GENS = {
    "mean" : lambda y,z : lambda x : x[y].mean(),
    "sum" : lambda y,z : lambda x : x[y].sum() ,
    "count" : lambda y,z : lambda x : x[y].count() ,
    "wmean" : lambda y,z : lambda x : (x[y] * x[z]).sum() / x[z].sum()
    }

    def my_summary (
    data ,
    var_names_in ,
    var_names_out ,
    var_functions ,
    var_name_weight = None ,
    var_names_group = None ):

    result = pd.DataFrame()

    if var_names_group is None:
    grouped = data.groupby (lambda x: True)
    else:
    grouped = data.groupby (var_names_group)

    for var_name_in, var_name_out, var_function in \
    zip(var_names_in,var_names_out,var_functions):
    func_gen = FUNC_GENS[var_function]
    func = func_gen (var_name_in, var_name_weight)
    result[var_name_out] = grouped.apply(func)

    return result

    2019年更新/当前解决方案

    在我的原始文章之后发布的 Pandas 版本现在实现了以下大多数功能:
  • 不进行分组-过去,Wes M.说过需要 DataFrame.agg() it was indeed added in version 0.20.0以及 Series.agg()
  • 多个列的多个聚合,并为输出列指定名称-这是now part of pandas as of version 0.25.+,形式为 NamedAgg inputs to the agg() function

  • 因此,除加权平均值外,基本上所有其他内容。当前的一个很好的解决方案是 here

    最佳答案

    好吧,这是一个确实可以解决两个问题的快捷方式(但对于加权均值仍然需要一个不同的功能)。通常,它使用here技巧(贷记@DSM)通过执行groupby(lamda x: True)来解决您的空组。如果在手段之类的东西上有一个“权重”的扭曲,但据我所知没有,那将是很棒的。显然有一个基于numpy的here加权分位数的程序包,但我对此一无所知。伟大的项目顺便说一句!

    (请注意,名称与您的名称基本相同,我只是在wmean_grouped和my_summary中添加了“2”,否则可以使用相同的调用接口(interface))

    def wmean_grouped2 (group, var_name_in, var_name_weight):
    d = group[var_name_in]
    w = group[var_name_weight]
    return (d * w).sum() / w.sum()

    FUNCS = { "mean" : np.mean ,
    "sum" : np.sum ,
    "count" : np.count_nonzero }

    def my_summary2 (
    data ,
    var_names_in ,
    var_names_out ,
    var_functions ,
    var_name_weight = None ,
    var_names_group = None ):

    result = pd.DataFrame()

    if var_names_group is None:
    grouped = data.groupby (lambda x: True)
    else:
    grouped = data.groupby (var_names_group)

    for var_name_in, var_name_out, var_function in \
    zip(var_names_in,var_names_out,var_functions):
    if var_function == "wmean":
    func = lambda x : wmean_grouped2 (x, var_name_in, var_name_weight)
    result[var_name_out] = pd.Series(grouped.apply(func))
    else:
    func = FUNCS[var_function]
    result[var_name_out] = grouped[var_name_in].apply(func)

    return result

    关于python - 在Python/Pandas中创建部分SAS PROC Summary替换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29926940/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com