Транспонировать кадр данных Python в соответствии со многими переменными

У меня есть Dataframe из одного файла, у меня есть продукты и цена вместе. У меня есть в файле за день, кто зарегистрировал все продукты, купленные клиентом. Таким образом, длина столбцов зависит от наибольшего количества товаров, купленных одним клиентом. В начале у меня есть такой файл:

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

Затем я разбиваю этот файл на «|», и после этого у меня есть 5 столбцов в моем новом файле df. потому что наибольшее количество товаров, купленных одним клиентом за этот день, равно 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

Но это не тот результат, который мне нужен.


person BENAMARA ILAN    schedule 24.05.2016    source источник


Ответы (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 теперь недокументирован, но возможно, в будущем будет удалено (с pd.wide_to_long тоже).

Возможное решение - объединить все 3 функции в одну - может быть melt, но сейчас это не реализовано. Может быть, в какой-то новой версии панд. Тогда мой ответ будет обновлен.

person jezrael    schedule 24.05.2016
comment
Спасибо, Израэль, я попробовал ваш код и забыл указать, что столбцы имеют разную длину. Это зависит от количества товара в корзине. Итак, Python отображает эту ошибку: все списки столбцов должны быть одинаковой длины - person BENAMARA ILAN; 24.05.2016
comment
Итак, некоторые столбцы, например. price_2 отсутствует? - person jezrael; 24.05.2016
comment
Да price_2 price_3...Price_n то же самое для продукта - person BENAMARA ILAN; 24.05.2016
comment
Итак, если я выберу столбцы, я получу что-то вроде: ['product_1', 'product_2', 'product_3', 'product_n'] ['price_1', 'price_2', 'price_n'] ? (без price_3) Столбцы имеют одинаковую структуру, разница только в последнем номере? Сколько столбцов для каждой категории? - person jezrael; 24.05.2016
comment
Нет, у меня есть product_1 до product_n , в моем файле у меня 24 столбца, а в другом файле у меня 30 столбцов. Как я уже сказал, это зависит от того, сколько продуктов кто-то купил в корзине. - person BENAMARA ILAN; 24.05.2016
comment
Можете ли вы добавить образец DataFrame, который вызывает ошибку? Я не понимаю. У вас все товары в одном файле и по другим ценам? Или в одном файле товары и цены вместе? - person jezrael; 24.05.2016
comment
В одном файле у меня есть товары и цена вместе. У меня есть в файле за день, кто зарегистрировал все продукты, купленные клиентом. Таким образом, длина столбцов зависит от наибольшего количества товаров, купленных одним клиентом. В начале у меня есть такой файл: date conv product Prices 01/2016 'part' A|B|C|E|F 15|20|30|40|50 01/2016 'Pro' D|B 10| 10 Затем я разбиваю этот файл на |, и после этого у меня есть 5 столбцов в моем новом файле df. потому что наибольшее количество товаров, купленных одним клиентом за этот день, равно 5. - person BENAMARA ILAN; 24.05.2016
comment
Я добавляю два возможных решения, пожалуйста, проверьте это. - person jezrael; 24.05.2016