2016-08-08 30 views
5

Müşterilere gönderilen faturaların bir listesini görüyorum. Ancak, bazen daha sonra iptal edilecek olan kötü bir fatura gönderilir. Benim Pandalar Dataframe çok daha büyük (~ 3 milyon satır) dışında böyle bir şey,Pandas Dataframe'den satırları iptal et Dataframe

index | customer | invoice_nr | amount | date 
--------------------------------------------------- 
0  | 1  | 1   | 10  | 01-01-2016 
1  | 1  | 1   | -10 | 01-01-2016 
2  | 1  | 1   | 11  | 01-01-2016 
3  | 1  | 2   | 10  | 02-01-2016 
4  | 2  | 3   | 7  | 01-01-2016 
5  | 2  | 4   | 12  | 02-01-2016 
6  | 2  | 4   | 8  | 02-01-2016 
7  | 2  | 4   | -12 | 02-01-2016 
8  | 2  | 4   | 4  | 02-01-2016 
... | ...  | ...  | ... | ... 
... | ...  | ...  | ... | ... 

Şimdi, customer, invoice_nr ve date özdeş oldukları tüm satırları damla istiyorum görünüyor, ama amount zıt değerlere sahip.
Faturaların düzeltmeleri her zaman aynı fatura numarasıyla aynı günde gerçekleşir. Fatura numarası müşteriye benzersiz bir şekilde bağlıdır ve her zaman bir işleme (örneğin customer = 2, invoice_nr = 4 için çoklu bileşenlerden oluşabilir) karşılık gelir. Fatura düzeltmeleri yalnızca amount numaralı ücreti değiştirmek veya amount'u daha küçük bileşenlerde ayırmak için oluşur. Bu nedenle, iptal edilen değer aynı invoice_nr'da tekrarlanmaz.

Bu programın nasıl yapılacağı ile ilgili yardımlar çok takdir edilecektir.

+0

deneyin "invoice_nr" ve "date" öğelerinin herhangi bir sınırlayıcı tarafından ayrıldığı bir 'dict'' '' dır. Artık herhangi bir yedek anahtar alırsanız, silin. –

+0

@KrishnachandraSharma Neyi kastettiğimi takip ettiğimden emin değilim. 'Invoice_nr' ve 'date'' dict' tuşları olarak mı okumalıyım? Daha sonra aynı "invoice_nr" ve "date" ile birden çok satırı nasıl işleyebilirim? –

+0

Tüm satırları aynı "invoice_nr" ve "date" ile bırakmak istediğinizden, anahtar dizesini "invoice_nr # date" olarak hazırlamak, düşürmek istediğiniz satırları tanımlamanıza yardımcı olur. –

cevap

2
def remove_cancelled_transactions(df): 
    trans_neg = df.amount < 0 
    return df.loc[~(trans_neg | trans_neg.shift(-1))] 

groups = [df.customer, df.invoice_nr, df.date, df.amount.abs()] 
df.groupby(groups, as_index=False, group_keys=False) \ 
    .apply(remove_cancelled_transactions) 

enter image description here

+0

Hmmm, bence bu daha karmaşık, çünkü karşıt değerler miktarını kaldırmanız gerekiyor. Ve çok zor ... – jezrael

+0

@jezrael sabit. – piRSquared

+0

Teşekkürler. Hmmm, bence çözümün daha iyi, çünkü daha genel. Benim çözümüm daha hızlı, ancak bazı değerler bulunamıyor. – jezrael

0

Sadece 3 alanın birinde bir groupby yaparsanız ne olur? her grup toplamı 0 olduğu değerlere sahip yerlerde, Sen filter tüm değerleri kullanabilirsiniz

customer invoice_nr date 
1  1   2016/01/01  11 
     2   2016/02/01  10 
2  3   2016/01/01  7 
+0

Teşekkürler, bu güzel bir çözüm. Ancak şimdi görüyorum, örnek verilerim yeterli değil, çünkü faturalarım zaman zaman ayrı olarak düşünmek istediğim küçük miktarlarda bölünüyor. Orijinal sorumu buna göre güncelledim. –

2

yılında

df2 = df.groupby(['customer','invoice_nr','date']).sum() 

sonuçları: Ortaya çıkan toplamlar herhangi iptal faturaları elde etmesini sağlayacak ve 2 tarafından modulo, 0:

'tür. Yoruma göre 63.210
print (df.groupby([df.customer, df.invoice_nr, df.date, df.amount.abs()]) 
     .filter(lambda x: (len(x.amount.abs()) % 2 == 0) and (x.amount.sum() == 0))) 

     customer invoice_nr amount  date 
index           
0    1   1  10 01-01-2016 
1    1   1  -10 01-01-2016 
5    2   4  12 02-01-2016 
6    2   4  -12 02-01-2016 

idx = df.groupby([df.customer, df.invoice_nr, df.date, df.amount.abs()]) 
     .filter(lambda x: (len(x.amount.abs()) % 2 == 0) and (x.amount.sum() == 0)).index 

print (idx)  
Int64Index([0, 1, 5, 6], dtype='int64', name='index') 

print (df.drop(idx)) 
     customer invoice_nr amount  date 
index           
2    1   1  11 01-01-2016 
3    1   2  10 02-01-2016 
4    2   3  7 01-01-2016 
7    2   4  8 02-01-2016 
8    2   4  4 02-01-2016 

DÜZENLEME:

bu şekilde kullanabilirsiniz kadar gerçek verilerde, tek fatura ve tek müşteri ve bir tarih için çiftleri değilseniz: satırları okumak için

print (df) 
    index customer invoice_nr amount  date 
0  0   1   1  10 01-01-2016 
1  1   1   1  -10 01-01-2016 
2  2   1   1  11 01-01-2016 
3  3   1   2  10 02-01-2016 
4  4   2   3  7 01-01-2016 
5  5   2   4  12 02-01-2016 
6  6   2   4  -12 02-01-2016 
7  7   2   4  8 02-01-2016 
8  8   2   4  4 02-01-2016 

df['amount_abs'] = df.amount.abs() 
df.drop_duplicates(['customer','invoice_nr', 'date', 'amount_abs'], keep=False, inplace=True) 
df.drop('amount_abs', axis=1, inplace=True) 
print (df) 
    index customer invoice_nr amount  date 
2  2   1   1  11 01-01-2016 
3  3   1   2  10 02-01-2016 
4  4   2   3  7 01-01-2016 
7  7   2   4  8 02-01-2016 
8  8   2   4  4 02-01-2016 
+0

Yardımlarınız için çok teşekkürler, Jezrael! @ PiRSquared'un çözümüne benzer şekilde, sizinki küçük veri kümesi için harika çalışıyor. Maalesef, 3 milyon satırlık veri ağım için, işlem oldukça uzun bir zaman alıyor. –

+0

Evet, göreviniz çok karmaşık. Yani daha hızlı bir şeye ihtiyaç varsa, sorunludur. Ancak bir soru - 3M sıralarında ne kadar sıklıkla iptal edilen faturalar (tahmini)? – jezrael

+0

Tüm çoğaltmaları ile df1'i alabilirsiniz: 'df ['amount_abs'] = df.amount.abs()' 'df1 = df [df.duplicated (['customer', 'invoice_nr', 'date', 'amount_abs'], tutmak = False)] ' ' print (df1)' df1'nin boyutu nedir? len (df1) ' – jezrael

İlgili konular