2016-05-03 11 views
1

Ich habe eine CSV Datei von monatlichen Handy Rechnungen in keiner bestimmten Reihenfolge, die ich in eine PandasDataframe lesen. Ich möchte für jede Rechnung eine Spalte hinzufügen, die angibt, wie stark sie sich von der vorherigen Rechnung für dasselbe Konto unterscheidet. Diese CSV ist nur eine Untermenge meiner Daten. Mein Code funktioniert gut, ist aber ziemlich schlampig und sehr langsam, wenn Sie eine CSV-Datei in der Nähe von einer Million Zeilen betrachten.Effizientes Vergleichen von Daten über Zeilen in einem Pandas Datareframe

Was soll ich tun, um dies effizienter zu machen?

CSV:

Account Number,Bill Month,Bill Amount 
4543,3/1/2015,300 
4543,1/1/2015,100 
4543,2/1/2015,200 
2322,1/1/2015,22 
2322,3/1/2015,38 
2322,2/1/2015,25 

Python:

import numpy as np 
import pandas as pd 
data = pd.read_csv('data.csv', low_memory=False) 

# sort my data and reset the index so I can use index and index - 1 in the loop 
data = data.sort_values(by=['Account Number', 'Bill Month']) 
data = data.reset_index(drop=True) 

# add a blank column for the difference 
data['Difference'] = np.nan 

for index, row in data.iterrows(): 

    # special handling for the first row so I don't get negative indexes 
    if index == 0: 
     data.ix[index, 'Difference'] = "-" 
    else: 
     # if the account in the current row and the row before are the same, then compare Bill Amounts 
     if data.ix[index, 'Account Number'] == data.ix[index - 1, 'Account Number']: 
      data.ix[index, 'Difference'] = data.ix[index, 'Bill Amount'] - data.ix[index - 1, 'Bill Amount'] 
     else: 
      data.ix[index, 'Difference'] = "-" 

print data 

gewünschte Ausgabe:

Account Number Bill Month Bill Amount Difference 
0   2322 1/1/2015   22   - 
1   2322 2/1/2015   25   3 
2   2322 3/1/2015   38   13 
3   4543 1/1/2015   100   - 
4   4543 2/1/2015   200  100 
5   4543 3/1/2015   300  100 

Antwort

1

try this:

In [37]: df = df.sort_values(['Account Number','Bill Month']) 

In [38]: df['Difference'] = (df.groupby(['Account Number'])['Bill Amount'] 
    ....:      .diff() 
    ....:      .fillna('-') 
    ....:     ) 

In [39]: df 
Out[39]: 
    Account Number Bill Month Bill Amount Difference 
3   2322 2015-01-01   22   - 
5   2322 2015-02-01   25   3 
4   2322 2015-03-01   38   13 
1   4543 2015-01-01   100   - 
2   4543 2015-02-01   200  100 
0   4543 2015-03-01   300  100 

Erläuterung:

diff() wird für jede Gruppe einzeln angewandt werden - es wird die Differenz zwischen dem „next“ Wert und dem aktuellen Wert zurück:

In [123]: df.groupby(['Account Number'])['Bill Amount'].diff() 
Out[123]: 
3  NaN 
5  3.0 
4  13.0 
1  NaN 
2 100.0 
0 100.0 
dtype: float64 

fillna('-') - füllt alle Nans mit dem angegebenen Wert: -:

In [124]: df.groupby(['Account Number'])['Bill Amount'].diff().fillna('-') 
Out[124]: 
3  - 
5  3 
4  13 
1  - 
2 100 
0 100 
dtype: object 
+0

Danke, das ist so sauber! Können Sie eine kurze Erklärung hinzufügen, wie 'df.diff()' weiß, welche Werte zu subtrahieren sind und wann 'fillna()' – user2242044

+0

@ user2242044 gilt, habe ich eine Erklärung zu meiner Antwort hinzugefügt - bitte überprüfen Sie – MaxU

+0

Danke für die explanation – user2242044

1
df = pd.DataFrame({ 
    'Account Number': {0: 4543, 1: 4543, 2: 4543, 3: 2322, 4: 2322, 5: 2322}, 
    'Bill Amount': {0: 300.0, 1: 100.0, 2: 200.0, 3: 22.0, 4: 38.0, 5: 25.0}, 
    'Bill Month': { 
     0: pd.Timestamp('2015-03-01 00:00:00'), 
     1: pd.Timestamp('2015-01-01 00:00:00'), 
     2: pd.Timestamp('2015-02-01 00:00:00'), 
     3: pd.Timestamp('2015-01-01 00:00:00'), 
     4: pd.Timestamp('2015-03-01 00:00:00'), 
     5: pd.Timestamp('2015-02-01 00:00:00')}} 

Sie können Gruppe auf Kontonummer und Abrechnungsmonat (standardmäßig sortiert), Summe der Rechnungsbetrag (oder nehmen Sie einfach den ersten, wenn Sie garantiert nur eine Rechnung pro Monat haben), gruppieren Sie erneut auf der ersten Ebene des Index (die Kontonummer), und nehmen Sie die Differenz mit diff.

>>> (df.groupby(['Account Number', 'Bill Month'])['Bill Amount'] 
     .sum() 
     .groupby(level=0) 
     .diff()) 
Account Number Bill Month 
2322   2015-01-01 NaN 
       2015-02-01  3 
       2015-03-01  13 
4543   2015-01-01 NaN 
       2015-02-01 100 
       2015-03-01 100 
+0

Danke, das ist großartig. In diesem Beispiel ist Kontonummer jetzt die Indexspalte? – user2242044

+0

Kontonummer und Rechnungsmonat. – Alexander

Verwandte Themen