美文网首页我爱编程
译:理解pandas中的tansform函数

译:理解pandas中的tansform函数

作者: mhye | 来源:发表于2017-06-12 16:10 被阅读264次

    原文链接:Understanding the Transform Function in Pandas

    transform示例

    引言

    pandas库拥有着丰富的方法操控数据,这是他的一大优势,但有时候,因为庞大的功能,你总会碰到一些不了解功能和用法的函数。如果你的大脑保持着Excel处理数据的思维惯性,在切换到pandas解决类似问题时就会遇到困难[1]transform就是这样一个函数。我已经使用pandas有一段时间了,但是还没有机会使用它,所我最近花了点时间去了解下他的用法,以及他能干些什么。这篇文章通过一个例子来演示transform如何在汇总数据时提示效率的。

    什么是transform?

    对于transform介绍的最好的是jake VanderPlas的书Python Data Science Handbook,就像书中提到的,transform函数是用来配合groupby操作的。这里假定大多数读者都可能都经常使用groupby中的aggregate,filter或者apply来汇总数据。但是transform跟这些相比理解起来有点小小困难,特别是对那些Excel用户来说。这里并不是说transform概念复杂,而是需要一个思路上的转换。jake将他的书已jupyter notebook形式发布,通过阅读可以了解下为什么transform'非常特别。

    aggregation操作返回压缩版本的数据,transformation可以返回经过完整数据经过转换的版本。经过转换,输出的数据和输入的数据结构相同

    With that basic definition, I will go through another example that can explain how this is useful in other instances outside of centering data.

    problem set

    在这个例子中,我们将会虚构一个销售数据:点我下载,为了节约篇幅,这里只保留12行。

    account name order sku quantity unit price ext price
    0 383080 Will LLC 10001 B1-20000 7 33.69 235.83
    1 383080 Will LLC 10001 S1-27722 11 21.12 232.32
    2 383080 Will LLC 10001 B1-86481 3 35.99 107.97
    3 412290 Jerde-Hilpert 10005 S1-06532 48 55.82 2679.36
    4 412290 Jerde-Hilpert 10005 S1-82801 21 13.62 286.02
    5 412290 Jerde-Hilpert 10005 S1-06532 9 92.55 832.95
    6 412290 Jerde-Hilpert 10005 S1-47412 44 78.91 3472.04
    7 412290 Jerde-Hilpert 10005 S1-27722 36 25.42 915.12
    8 218895 Kulas Inc 10006 S1-27722 32 95.66 3061.12
    9 218895 Kulas Inc 10006 B1-33087 23 22.55 518.65
    10 218895 Kulas Inc 10006 B1-33364 3 72.30 216.90
    11 218895 Kulas Inc 10006 B1-20000 -1 72.18 -72.18

    如果所见,表中有三个订单(10001, 10005 and 10006) ,每个订单包含多个产品。

    现在我们想通过以上数据知道:每个产品占总订单百分比
    例如,加入我们知道订单10001总计金额是576.12,那么这个订单下面每个产品的价值比例依次是。

    • B1-20000 = $235.83 or 40.9%
    • S1-27722 = $232.32 or 40.3%
    • B1-86481 = $107.97 or 18.7%
      通常要计算这些信息,并且添加到原表中应该如何实现呢?先计算每个订单的总价,然后将这些数据置回明细表,得到百分比。在Excel中,你可以通过分类汇总计算值。

    第一种方法-合并

    如果你非常熟悉pandas,你可能会先进行分组,得到一个新的DataFrame,然后进行合并,经过系列步骤得到最终结果,你可能通常是这样擦做的
    导入模块,读取数据

    import pandas as pd
    df = pd.read_excel("sales_transactions.xlsx")
    

    然后,你会通过groupby根据订单号进行分组,然后使用sum函数对价格进行汇总。

    df.groupby('order')["ext price"].sum()
    order
    10001     576.12
    10005    8185.49
    10006    3724.49
    Name: ext price, dtype: float64
    

    下面这张图演示了进行groupby操作时发生了什么。

    groupby:split、apply、combine
    最关键的部分是,如何将分组后的计算结果拼接到原始数据中,本能的想法是利用聚合数据创建一个新的dataframe,然后通过merge执行右连接拼接到原始数据。
    order_total = df.groupby('order')["extprice"].sum().rename("Order_Total").reset_index()
    df_1 = df.merge(order_total)
    #merge的时候省略了一些细节,因为有共同字段Order,所以自动对齐,实际上相当于df.merge(order_total,on ='order',how = left)
    df_1["Percent_of_Order"] = df_1["ext price"] / df_1["Order_Total"]
    
    account name order sku quantity unit price ext price order total Order_Total Percent_of_Order
    0 383080 Will LLC 10001 B1-20000 7 33.69 235.83 576.12 576.12 0.409342
    1 383080 Will LLC 10001 S1-27722 11 21.12 232.32 576.12 576.12 0.403249
    2 383080 Will LLC 10001 B1-86481 3 35.99 107.97 576.12 576.12 0.187409
    3 412290 Jerde-Hilpert 10005 S1-06532 48 55.82 2679.36 8185.49 8185.49 0.327330
    4 412290 Jerde-Hilpert 10005 S1-82801 21 13.62 286.02 8185.49 8185.49 0.034942
    5 412290 Jerde-Hilpert 10005 S1-06532 9 92.55 832.95 8185.49 8185.49 0.101759
    6 412290 Jerde-Hilpert 10005 S1-47412 44 78.91 3472.04 8185.49 8185.49 0.424170
    7 412290 Jerde-Hilpert 10005 S1-27722 36 25.42 915.12 8185.49 8185.49 0.111798
    8 218895 Kulas Inc 10006 S1-27722 32 95.66 3061.12 3724.49 3724.49 0.821890
    9 218895 Kulas Inc 10006 B1-33087 23 22.55 518.65 3724.49 3724.49 0.139254
    10 218895 Kulas Inc 10006 B1-33364 3 72.30 216.90 3724.49 3724.49 0.058236
    11 218895 Kulas Inc 10006 B1-20000 -1 72.18 -72.18 3724.49 3724.49 -0.019380

    这样当然没问题,但是要经过很多中介步骤。

    第二种方法:使用Transform

    使用之前的数据,我们看看transformgroupby能得到什么

    df.groupby('order')["ext price"].transform('sum')
    
    0      576.12
    1      576.12
    2      576.12
    3     8185.49
    4     8185.49
    5     8185.49
    6     8185.49
    7     8185.49
    8     3724.49
    9     3724.49
    10    3724.49
    11    3724.49
    dtype: float64
    

    你可以看到,单纯的groupby进行sum聚合得到的数据尺寸和transform不同。普通聚合函数返回聚合以后的结果,而transform返回的计算结果保留的原始数据的索引,这就是transform的独特性。
    借此,我们可以不用费什么脑子,两部结算处结果

    df["Order_Total"] = df.groupby('order')["ext price"].transform('sum')
    df["Percent_of_Order"] = df["ext price"] / df["Order_Total"]
    
    account name order sku quantity unit price ext price order total Order_Total Percent_of_Order
    0 383080 Will LLC 10001 B1-20000 7 33.69 235.83 576.12 576.12 0.409342
    1 383080 Will LLC 10001 S1-27722 11 21.12 232.32 576.12 576.12 0.403249
    2 383080 Will LLC 10001 B1-86481 3 35.99 107.97 576.12 576.12 0.187409
    3 412290 Jerde-Hilpert 10005 S1-06532 48 55.82 2679.36 8185.49 8185.49 0.327330
    4 412290 Jerde-Hilpert 10005 S1-82801 21 13.62 286.02 8185.49 8185.49 0.034942
    5 412290 Jerde-Hilpert 10005 S1-06532 9 92.55 832.95 8185.49 8185.49 0.101759
    6 412290 Jerde-Hilpert 10005 S1-47412 44 78.91 3472.04 8185.49 8185.49 0.424170
    7 412290 Jerde-Hilpert 10005 S1-27722 36 25.42 915.12 8185.49 8185.49 0.111798
    8 218895 Kulas Inc 10006 S1-27722 32 95.66 3061.12 3724.49 3724.49 0.821890
    9 218895 Kulas Inc 10006 B1-33087 23 22.55 518.65 3724.49 3724.49 0.139254
    10 218895 Kulas Inc 10006 B1-33364 3 72.30 216.90 3724.49 3724.49 0.058236
    11 218895 Kulas Inc 10006 B1-20000 -1 72.18 -72.18 3724.49 3724.49 -0.019380

    如果你不需要中间字段(汇总字段),可以一步得出百分比

    df["Percent_of_Order"] = df["ext price"] / df.groupby('order')["ext price"].transform('sum')
    

    下图演示了transform的工作逻辑,可以对照下之前groupby

    transform-example.png
    通过上面的例子,我相信你也认为transform功能非常强大。

    译者讨论

    以前我解决这类问题的思路是先groupby,然后通过自己写的lambda函数查找到结果在apply到新列中,通过第一个例子,才知道merge原来是这样用的,缺少sql的思维真是害死人。


    1. 这段翻译可能谬误比较大

    相关文章

      网友评论

        本文标题:译:理解pandas中的tansform函数

        本文链接:https://www.haomeiwen.com/subject/qyxlqxtx.html