【问题标题】:Transpose a Python Dataframe according many variables根据许多变量转置 Python Dataframe
【发布时间】:2016-09-21 06:59:54
【问题描述】:

我有一个来自一个文件的数据框,我有产品和价格。我每天都有记录客户购买的所有产品的人。所以列的长度取决于一个客户购买的最大产品数量。一开始,我有一个这样的文件:

date     conv   product      Prices 
01/2016 'part ' A|B|C|E|F 15|20|30|40|50 
01/2016 'Pro'   D|B       10|10 

然后我用“|”分割那个文件,然后我的新 df 上有 5 列。因为一个客户当天购买的最大产品数量是5。

最终的 DataFrame 给出:

Date     Conv    Product_1 product_2 ... product_n  price_1  price_2 ... price_n
01/2016  'Part'        A        B           C            15      20          30 
01/2016  'Pro'         B        D           C            10      10          20 
02/2016  'Part'        E        A           B            25      5           10 

我想转置变量“Product_1 ...product_n”和“price 1 ... price_n”。并获得一个新的 df :

Date      Conv   Product   price 
01/2016  'Part'     A        15
01/2016  'Part'     B        20
01/2016  'Part'     C        30
01/2016  'Pro'      B        10
01/2016  'Pro'      D        10
01/2016  'Pro'      C        20
02/2016  'Part'     E        25
02/2016  'Part'     A         5
02/2016  'Part'     B        10

困难在于转置变量并复制变量Date和conv。

我认为使用SAS 我们可以通过代码获得:

Proc transpose ; 
Data = DF;
VAR product_1-product_4 price1_price_4;
BY Date Conv;
COPY Date Conv;

但在 Python 上我没有找到等价物。

有人知道我该怎么做吗?

我尝试使用:df.transpose

但这不是我想要的结果。

【问题讨论】:

    标签: python pandas sas reshape transpose


    【解决方案1】:

    您可以先通过list 理解和startswith 选择列,然后使用pd.lreshape

    prods = ([col for col in df.columns if col.startswith('product_')])
    prices = ([col for col in df.columns if col.startswith('price_')])
    
    print (prods)
    ['product_1', 'product_2', 'product_n']
    print (prices)
    ['price_1', 'price_2', 'price_n']
    
    df1 = pd.lreshape(df, {'product' : prods, 'price' : prices}) 
    print (df1)
         Conv     Date  price product
    0  'Part'  01/2016     15       A
    1   'Pro'  01/2016     10       B
    2  'Part'  02/2016     25       E
    3  'Part'  01/2016     20       B
    4   'Pro'  01/2016     10       D
    5  'Part'  02/2016      5       A
    6  'Part'  01/2016     30       C
    7   'Pro'  01/2016     20       C
    8  'Part'  02/2016     10       B
    

    通过更具体的问题进行编辑:

    #new df1 from column product
    df1 = (df['product'].str.split('|', expand=True))
    #add prod_ to column names
    prods = df1.columns = ['prod_' + str(col) for col in df1.columns] 
    
    #new df2 from column Prices
    df2 = (df['Prices'].str.split('|', expand=True))
    #add part_ to column names
    prices = df2.columns = ['part_' + str(col) for col in df2.columns]
    
    #join all together
    df3 = (pd.concat([df[['date','conv']], df1, df2], axis=1))
    
    #reshape
    print (pd.lreshape(df3, {'product' : prods, 'price' : prices}))
         conv     date price product
    0  'part'  01/2016    15       A
    1   'pro'  01/2016    10       D
    2  'part'  01/2016    20       B
    3   'pro'  01/2016    10       B
    4  'part'  01/2016    30       C
    5  'part'  01/2016    40       E
    6  'part'  01/2016    50       F
    

    join 的另一个解决方案:

    #create dataframe and stack, drop level of multiindex
    s1 = (df['product'].str.split('|', expand=True)).stack()
    s1.index = s1.index.droplevel(-1)
    s1.name = 'product'
    
    s2 = (df['Prices'].str.split('|', expand=True)).stack()
    s2.index = s2.index.droplevel(-1)
    s2.name = 'price'
    
    #remove original columns    
    df = df.drop(['product','Prices'], axis=1)
    
    #join series to dataframe    
    df1 = (df.join(s1).reset_index(drop=True))
    df2 = (df.join(s2).reset_index(drop=True))
    
    #join all togehter
    print (pd.concat([df1, df2[['price']]], axis=1))
          date    conv product price
    0  01/2016  'part'       A    15
    1  01/2016  'part'       B    20
    2  01/2016  'part'       C    30
    3  01/2016  'part'       E    40
    4  01/2016  'part'       F    50
    5  01/2016   'pro'       D    10
    6  01/2016   'pro'       B    10
    

    时间安排

    In [598]: %timeit (a(df))
    100 loops, best of 3: 10.6 ms per loop
    
    In [599]: %timeit (b(df_a))
    100 loops, best of 3: 14.1 ms per loop
    

    计时码

    import pandas as pd
    
    df = pd.DataFrame({'date': {0: '01/2016', 1: '01/2016'}, 
                       'conv': {0: "'part'", 1: "'pro'"}, 
                       'Prices': {0: '15|20|30|40|50', 1: '10|10'}, 
                       'product': {0: 'A|B|C|E|F', 1: 'D|B'}}, 
                        columns =['date','conv','product','Prices'])
    
    df = pd.concat([df]*1000).reset_index(drop=True)
    
    print (df)
    df_a = df.copy()
    
    def a(df):
        df1 = (df['product'].str.split('|', expand=True))
        prods = df1.columns = ['prod_' + str(col) for col in df1.columns] 
    
        df2 = (df['Prices'].str.split('|', expand=True))
        prices = df2.columns = ['part_' + str(col) for col in df2.columns]
    
        df3 = (pd.concat([df[['date','conv']], df1, df2], axis=1))
    
        return (pd.lreshape(df3, {'product' : prods, 'price' : prices}))
    
    
    def b(df):
        s1 = (df['product'].str.split('|', expand=True)).stack()
        s1.index = s1.index.droplevel(-1)
        s1.name = 'product'
    
        s2 = (df['Prices'].str.split('|', expand=True)).stack()
        s2.index = s2.index.droplevel(-1)
        s2.name = 'price'
    
        df = df.drop(['product','Prices'], axis=1)
    
        df1 = (df.join(s1).reset_index(drop=True))
        df2 = (df.join(s2).reset_index(drop=True))
    
        return (pd.concat([df1, df2[['price']]], axis=1))
    
    print (a(df))    
    print (b(df_a))  
    

    编辑:

    lreshape 现在没有记录,但将来可能会被删除 (with pd.wide_to_long too)。

    可能的解决方案是将所有 3 个功能合并为一个 - 可能是 melt,但现在尚未实施。也许在一些新版本的熊猫中。然后我的答案会更新。

    【讨论】:

    • 感谢 Jezrael,我尝试了您的代码,但我忘了指定列的长度不同。这取决于篮子上的产品数量。因此 Python 显示该错误:所有列列表必须相同长度
    • 所以有些列,例如price_2 不见了?
    • 是的 price_2 price_3...Price_n 与产品相同
    • 好的,所以如果我选择列,我会得到类似:['product_1', 'product_2', 'product_3', 'product_n'] ['price_1', 'price_2', 'price_n'] ? (没有price_3)列具有相同的结构,只有最后一个数字不同?每个类别有多少列?
    • 不,我有 product_1 直到 product_n ,在我的文件中我有 24 列,但在另一个文件中我有 30 列。就像我说的,这取决于一个人在一个篮子里买了多少产品。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-09
    • 2012-09-01
    • 2017-08-29
    • 2021-06-21
    • 2022-01-24
    • 2016-07-20
    • 1970-01-01
    相关资源
    最近更新 更多