2017-09-29 2 views
1

Ich habe zwei Pandas-Datenframes, die ich zusammenführen muss. Der erste ist ein Langform-Datensatz, der meine Verkaufspreise für Artikel zu verschiedenen Mengenpausen enthält. Die Preise sinken, wenn die Anzahl der gekauften Teile steigt.Pandas verschmelzen, skalieren und drehen Langform- und Wide-Form-Datenframes

Dataframe1

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

Die zweite ist eine weit Form Datensatz mehrere Lieferanten Menge Pausen und Verkaufspreise enthalten. Für Item1 unten, wenn ich 1 Stück von Vend1 kaufe, bezahle ich $ 10, 4 Stück ist immer noch $ 10, 5pcs ist $ 8, etc. Die Anzahl der Anzahl Brüche variiert nach Artikel und Anbieter, und nicht alle Anbieter verkaufen alle Artikel.

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 

Ich mag den Datenrahmen fusionieren, so dass ich meinen Verkaufspreis bei jedem meiner Menge breche mit dem Verkäufer Kosten bei gleichen Mengen vergleichen. Der endgültige Datenrahmen wird die Form einer linken Zusammenführung auf TEIL # haben, wobei VEND # zu Spalten geschwenkt wird.

Der Teil, mit dem ich Schwierigkeiten habe, ist das Ergreifen des korrekten Lieferantenpreises basierend auf MY_QTY. Ich sollte in der Lage sein, quer durch eine Reihe zu lesen und zu sehen, was alle Parteien für einen Gegenstand in der gegebenen Menge verlangen. Erwartete Ausgabe unten.

Ergebnis Datenrahmen

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

scheinen Menschen mit Dataframe2 werden immer verwirrt. Dieser Datenrahmen wird zeilenweise gelesen. Die erste Reihe der Werte zeigt die Preise für Artikel1, die von Verkauf1 verkauft werden. Für diese Reihe von QTY1 (1 Stück) bis QTY2 (5 Stück) ist der Preis PRC1 ($ 10), dann von QTY2 (5 Stück) bis QTY3 (15 Stück) ist der Preis PRC2 ($ 8). Der Preis bleibt gleich, bis die angeforderte Menge die nächste Mengenpause erreicht.

Say Mama Farmstand verkauft Äpfel für $ 1 pro Stück. Wenn Sie 5 Äpfel kaufen, fällt der Preis pro Apfel auf $ 0,75. Wenn Sie 15 Äpfel kaufen, fällt der Preis wieder auf $ 0,50. Der Datenrahmen für dieses Beispiel würde wie folgt aussehen.

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

In der zweiten Reihe sortiert werden 'MY_QTY' ist' 10' und wie '' VEND1' 8 'es gibt keinen Preis für QTY 10 na – Dark

+0

Möglich, Ihren aktuellen Code zu teilen und welche Fehler Sie laufen? – ShreyasG

+0

interagiert der 'QTY1' im zweiten Datenframe überhaupt mit dem Ergebnisdatenrahmen? – MattR

Antwort

1

Hier ist eine andere Art und Weise, die nur Schleifen über den Anbieter verwendet, erfordert jedoch die Daten

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

Dies funktionierte perfekt auf dem großen Datensatz. Danke für die Hilfe Keith. Sehr geschätzt. –

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

Das funktioniert, weil die Länge der dfs gleich ist, so dass wir am Index teilnehmen können. Wenn dies bei Ihren tatsächlichen Datensätzen nicht der Fall ist, werde ich meine Antwort entsprechend bearbeiten. –

1

Hier ist ein funktionierendes Beispiel dafür, wie Sie es tun könnte. Dies ist keineswegs effizient. Andere Leute scheinen versucht zu sein, die beiden Datensätze zu verbinden, aber es klingt wie, was Sie wollten, war tatsächlich den Preis der größten QTY <= MY_QTY für jeden Anbieter/Teil Kombination.

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

Vielen Dank für die Antwort. Ich glaube, dass dies die richtige Ausgabe liefert und ich habe tatsächlich einen sehr ähnlichen iterativen Ansatz bei meinem ersten Durchlauf des Problems geschrieben. Ich arbeite jedoch mit einem großen Dataset und das und mein Original benötigen beide sehr viel Zeit. In der Hoffnung, die Iteration so weit wie möglich zu vermeiden. –

+0

Pandas merge_asof könnte dafür funktionieren: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.merge_asof.html – Keith

Verwandte Themen