2017-09-29 7 views
1

J'ai deux bases de données Pandas dont j'ai besoin pour fusionner. Le premier est un ensemble de données à long formulaire contenant mes prix de vente pour les articles à diverses ruptures de quantité. Les prix diminuent à mesure que la quantité de pièces achetées augmente.Les Pandas fusionnent, mettent à l'échelle et pivotent des structures de données de forme longue et de forme large

Dataframe1

PART# MY_QTY MY_PRC 
Item1 1  $20 
Item1 10  $18 
Item1 20  $17 
Item2 1  $120 
Item2 30  $100 
Item2 50  $95 

Le second est un ensemble de données large forme contenant de multiples ruptures de quantité de vendeur et les prix de vente. Pour Item1 ci-dessous si j'achète 1 pièce de Vend1 je paye 10 $, 4 pcs est encore 10 $, 5pcs est 8 $, etc. Le nombre de pauses varie selon l'article et le vendeur, et tous les vendeurs ne vendent pas tous les articles.

Dataframe2

PART# VEND# QTY1 PRC1 QTY2 PRC2 QTY3 PRC3 
Item1 Vend1 1 $10  5  $8  15 $7 
Item1 Vend2 1 $15  11 $12  30 $11 
Item1 Vend3 1 $20  10 $18 
Item2 Vend1 1 $75  20 $60  30 $55 
Item2 Vend2 1 $80  12 $70 

Je veux fusionner les dataframes afin que je puisse comparer mon prix de vente à chacun de mes quantité rompt avec les coûts des fournisseurs aux mêmes quantités. La structure de données finale aura la forme d'une fusion à gauche sur PART # avec les colonnes pivotées de VEND #.

La partie avec laquelle je suis en difficulté est de saisir le prix correct du fournisseur basé sur MY_QTY. Je devrais être capable de lire à travers une rangée et de voir ce que toutes les parties facturent pour un article à la quantité donnée. Sortie attendue ci-dessous.

Résultat dataframe

PART# MY_QTY MY_PRC VEND1 VEND2 VEND3 
Item1 1  $20  $10  $15  $20 
Item1 10  $18  $8  $15  $18 
Item1 20  $17  $7  $12  $18 
Item2 1  $120  $75  $80 
Item2 30  $100  $55  $70 
Item2 50  $95  $55  $70 

EDIT

Les gens semblent se confondre avec Dataframe2. Cette base de données est lue en ligne. La première ligne de valeurs indique les prix pour Item1 vendus par Vend1. Pour cette rangée de QTY1 (1 pièce) jusqu'à QTY2 (5 pièces) le prix est PRC1 (10 $), puis de QTY2 (5 pièces) jusqu'à QTY3 (15 pièces) le prix est PRC2 (8 $). Le prix reste le même jusqu'à ce que la quantité demandée atteigne la prochaine rupture de quantité.

Say Mama's Farm Stand vend des pommes pour 1 $ chacune. Si vous achetez 5 pommes, le prix par pomme tombe à 0,75 $. Si vous achetez 15 pommes, le prix baisse de nouveau à 50 $. Le dataframe pour cet exemple ressemblerait à ci-dessous.

PART# VEND# QTY1 PRC1 QTY2 PRC2 QTY3 PRC3 
Apple Mama 1  $1  5  $.75 15  $.5 
+0

Dans la deuxième ligne '' MY_QTY' est 10' et comment est '' 8 VEND1' 'il n'y a pas de prix pour QTY 10 na – Dark

+0

Possible de partager votre code actuel et quelles sont les erreurs que vous rencontrez? – ShreyasG

+0

est-ce que le 'QTY1' dans la deuxième image interagit avec la trame de données de résultat? – MattR

Répondre

1

Voici une autre façon qui utilise uniquement les boucles sur le vendeur, mais exige que les données à trier

import pandas as pd 
from io import StringIO 
import numpy as np 

df1_t = StringIO("""PART#,MY_QTY,MY_PRC 
Item1,1,$20 
Item1,10,$18 
Item1,20,$17 
Item2,1,$120 
Item2,30,$100 
Item2,50,$95 
""") 

df2_t = StringIO("""PART#,VEND#,QTY1,PRC1,QTY2,PRC2,QTY3,PRC3 
Item1,Vend1,1,$10,5,$8,15,$7 
Item1,Vend2,1,$15,11,$12,30,$11 
Item1,Vend3,1,$20,10,$18 
Item2,Vend1,1,$75,20,$60,30,$55 
Item2,Vend2,1,$80,12,$70 
""") 

df1 = pd.read_csv(df1_t) 
df2 = pd.read_csv(df2_t) 


df2 = pd.wide_to_long(df2, ['QTY','PRC'], i='VEND#', j='v').set_index('QTY',append=True).reset_index().drop('v', 
    axis=1) 
df1['MY_QTY'] = df1['MY_QTY'].astype(float) 
df1 = df1.sort_values(by="MY_QTY") 
df2 = df2.sort_values(by="QTY") 
df2 = df2.dropna(axis=0, how='any') 

vendors = df2['VEND#'].unique() 
df3=df1 
for vendor in vendors: 
    df3 = pd.merge_asof(df3, df2[df2['VEND#']==vendor], left_on="MY_QTY", right_on="QTY", by='PART#',suffixes=('', '_y')) 

to_drop = [x for x in df3 if x.startswith('VEND')] 
to_drop = to_drop + [x for x in df3 if x.startswith('QTY')] 
df3.drop(to_drop, axis=1, inplace=True) 
df3 = df3.rename(columns={prc : vendor for prc, vendor in zip([x for x in df3 if x.startswith('PRC')], vendors)}) 

print(df3) 
#  PART# MY_QTY MY_PRC Vend1 Vend3 Vend3 
#0 Item1  1.0 $20 $10 $15 $20 
#1 Item2  1.0 $120 $75 $80 NaN 
#2 Item1 10.0 $18 $8 $15 $18 
#3 Item1 20.0 $17 $7 $12 $18 
#4 Item2 30.0 $100 $55 $70 NaN 
#5 Item2 50.0 $95 $55 $70 NaN 
+0

Cela a fonctionné parfaitement sur le grand ensemble de données. Merci pour l'aide Keith. Très apprécié. –

0
dfs = [] 
for val in ['PRC1','PRC2','PRC3']:  
    temp = pd.pivot_table(df2, index='PART#', columns='VEND#', values=val).reset_index() 
    dfs.append(temp) 
pivot = pd.concat(dfs, axis=0) 
pivot.sort_values('PART#',inplace=True) 
pivot.reset_index(inplace=True) 
df1.join(pivot,lsuffix='PART#') 
+0

Cela fonctionne parce que la longueur de la dfs est la même que nous sommes en mesure de rejoindre sur l'index, si ce n'est pas le cas avec vos données réelles, je vais modifier ma réponse en conséquence. –

1

Voici un exemple concret de la façon dont vous pourriez le faire. Ce n'est en aucun cas efficace. D'autres personnes semblaient essayer de joindre les deux ensembles de données, mais il semble que ce que vous vouliez était en fait d'obtenir le prix le plus élevé pour chaque combinaison fournisseur/pièce.

import pandas as pd 
from io import StringIO 
import numpy as np 

df1_t = StringIO("""PART#,MY_QTY,MY_PRC 
Item1,1,$20 
Item1,10,$18 
Item1,20,$17 
Item2,1,$120 
Item2,30,$100 
Item2,50,$95 
""") 

df2_t = StringIO("""PART#,VEND#,QTY1,PRC1,QTY2,PRC2,QTY3,PRC3 
Item1,Vend1,1,$10,5,$8,15,$7 
Item1,Vend2,1,$15,11,$12,30,$11 
Item1,Vend3,1,$20,10,$18 
Item2,Vend1,1,$75,20,$60,30,$55 
Item2,Vend2,1,$80,12,$70 
""") 

df1 = pd.read_csv(df1_t) 
df2 = pd.read_csv(df2_t) 

vendors = df2['VEND#'].unique() 
items = df2['PART#'].unique() 

# for the specific item and vendor in the rows of Dataframe1 (df1), find the 
# largest QTY for that that's less than MY_QTY for the same combination of item 
# and vendor in df2 
def find_price(row, vendor, df2): 
    item = row['PART#'] 
    quantity = row['MY_QTY'] 
    # get the row with that specific item/vendor combo 
    prices = df2[(df2['PART#']==item) & (df2['VEND#']==vendor)] 
    # reshape a little 
    prices = pd.wide_to_long(prices, ['QTY','PRC'], i='VEND#', j='v').set_index('QTY',append=True).reset_index().drop('v',axis=1) 
    # only get where QTY <= MY_QTY 
    prices = prices[prices['QTY']<=quantity] 
    if prices.empty: 
     return np.nan 
    else: 
     return prices.loc[prices['QTY'].argmax(),:]['PRC'] 


# iterate throw the vendors, and use find_price to get the corresponding price 
for vendor in vendors: 
    df1[vendor] = df1.apply(lambda row: find_price(row, vendor, df2),axis=1) 

print(df1) 
# PART# MY_QTY MY_PRC Vend1 Vend2 Vend3 
#0 Item1  1 $20 $10 $15 $20 
#1 Item1  10 $18 $8 $15 $18 
#2 Item1  20 $17 $7 $12 $18 
#3 Item2  1 $120 $75 $80 NaN 
#4 Item2  30 $100 $55 $70 NaN 
#5 Item2  50 $95 $55 $70 NaN 
+0

Merci beaucoup pour la réponse. Je crois que ceci obtient la sortie correcte et j'ai réellement écrit une approche itérative très semblable sur ma première exécution au problème. Je travaille avec un grand ensemble de données mais cela et mon original prennent beaucoup de temps à courir. Espérant éviter l'itération autant que possible. –

+0

Pandas merge_asof pourrait fonctionner pour ceci: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.merge_asof.html – Keith