Вы можете сначала выбрать столбцы по 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