Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/298.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python/Pandas中创建部分SAS PROC摘要替换_Python_Pandas - Fatal编程技术网

在Python/Pandas中创建部分SAS PROC摘要替换

在Python/Pandas中创建部分SAS PROC摘要替换,python,pandas,Python,Pandas,我们正在努力摆脱SAS,进入Python/Pandas。然而,有一件事我们遇到了麻烦,那就是为具有SAS例程灵活性的PROC SUMMARY(又名PROC MEANS)创建一个替代品。对于非SAS用户:PROC SUMMARY只是一个例程,它在数据集中生成一个表,其中包含“所有观察值或观察值组内变量的描述性统计数据”,以解释SAS文档。我们的需求只是完整功能的一小部分—输出一个表,其中包含: 能够将不同的统计数据应用于不同的列(现在只需计数、求和、平均值、加权平均值) 能够处理零到多个分组变量

我们正在努力摆脱SAS,进入Python/Pandas。然而,有一件事我们遇到了麻烦,那就是为具有SAS例程灵活性的
PROC SUMMARY
(又名
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\u 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()
有效,但正如您所见,它的实现并不是最漂亮的。以下是主要问题:

  • 两种不同的代码路径取决于分组或非分组-这完全是因为
    DataFrame
    DataFrameGroupBy
    对单个列应用编程选择的缩减函数有不同的方法。对于
    DataFrame
    ,我找到的唯一方法是直接调用
    func(data[var\u name\u in])
    <代码>数据[var\u name\u in].apply(func)不起作用,因为
    系列上的
    apply()
    不会减少(与
    数据帧上的
    apply()
    不同)。另一方面,对于
    DataFrameGroupBy
    ,我必须使用这种方法:
    grouped[var\u name\u in].apply(func)
    。这是因为像
    func(grouped[var\u name\u in])
    这样的东西不起作用(没有理由)
  • 加权平均值的特殊处理-这是因为它在两列上运行,而所有其他计算只在一列上运行;我不知道这是否有帮助
  • 两个不同的加权平均值函数-这是第一个问题的结果。未分组的函数具有
    系列
    类型的参数,需要
    dot()
    进行乘法和减法运算;分组函数最终处理
    序列groupby
    对象,并且必须使用
    *
    运算符(对加权平均函数代码的确认)
因此,我的问题是:

  • 有没有熊猫特有的东西可以做到这一切(即扔掉上面的东西,改用它)
  • 如果没有,上述问题是否有任何解决方案
  • 很可能,有没有什么方法可以进行分组?也就是说,从
    DataFrame
    对象中获取
    DataFrameGroupBy
    对象,而无需对任何变量进行分组?然后,代码路径将减少,因为我们将专门处理
    DataFrameGroupBy
    接口
更新(旧版-向下滚动查看当前版本) @约翰的回答提供了一种无需分组的方法:
groupby(lambda x:True)
。这是他发现的一个变通方法(顺便说一句,它的特点是Wes自己回答说需要一个
DataFrame.agg()
,这将达到同样的目的)@JohnE的优秀解决方案允许我们专门处理类型为
DataFrameGroupBy
的对象,并立即减少大部分代码路径。我能够使用一些功能性的噱头来进一步降低成本,这现在是可能的,因为我们只有
DataFrameGroupBy
实例。基本上,所有函数都是根据需要生成的,“生成器”(此处引用以避免与Python生成器表达式混淆)有两个参数:值列名和权重列名,除
wmean
外,第二个参数在所有情况下都会被忽略。生成的函数始终应用于整个
DataFrameGroupBy
,就像最初的
wmean
一样,参数是要使用的正确列名。我还用pandas计算替换了所有的
np.*
实现,以便更好地处理
NaN

除非有熊猫特有的东西可以做到这一点,否则这就是我们的解决方案:

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.过去曾说过需要一个and和一个and
  • 多个列的多个聚合,并为输出列指定名称-其形式为

所以,基本上,除了加权平均数之外,其他都是。一个很好的当前解决方案是。

好吧,这里有一个快速解决方案,可以解决两个问题(但仍然需要一个不同的加权平均值函数)。大多数情况下,它使用技巧(归功于@DSM)通过执行
groupby(lamda x:True)
绕过您的空组。如果在诸如手段之类的东西上有“权重”的夸克,那就太好了,但据我所知,没有。显然有一个基于numpy的加权分位数包,但我对此一无所知。伟大的项目顺便说一句

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


正如旁白
df.descripe()
将为您提供状态摘要一样,这太棒了。
groupby(lambda x:True)
hack只是一个技巧,开启了一个全新的可能性领域。我也很感谢您链接到
groupby(None)
问题,其中包括韦斯本人的回答,他补充道
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