2016-09-02 13 views
5

Robię nieco bardziej skomplikowaną operację na ramce danych, w której porównuję dwa wiersze, które mogą znajdować się w dowolnym miejscu ramki.Pandy: Uzyskaj jedyną wartość serii lub nan, jeśli nie istnieje

Oto przykład:

import pandas as pd 
import numpy as np 

D = {'A':['a','a','c','e','e','b','b'],'B':['c','f','a','b','d','a','e']\ 
,'AW':[1,2,3,4,5,6,7],'BW':[10,20,30,40,50,60,70]} 
P = pd.DataFrame(D) 
P = P.sort_values(['A','B']) 
P['AB'] = P.A+'_'+P.B 
P['AWBW'] = P.AW+P.BW 

co teraz robię jest to, że mam powiązania ciągów w A i B np a_c który nazywam AB. Mam również odwrotne powiązanie c_a. Suma liczb AW i BW dla każdego parowania, o nazwie AWBW.

Teraz chcę odjąć zsumowaną wartość a_c od wartości c_a i zrobić to samo dla każdego parowania ciągów, w których istnieją oba warianty. Wszystkie inne wartości powinny być tylko NaN, więc mój wynik powinien wyglądać następująco:

A AW B BW AB AWBW RowDelta 
0 a 1 c 10 a_c 11  -22.0 
1 a 2 f 20 a_f 22  NaN 
5 b 6 a 60 b_a 66  NaN 
6 b 7 e 70 b_e 77  33.0 
2 c 3 a 30 c_a 33  22.0 
3 e 4 b 40 e_b 44  -33.0 
4 e 5 d 50 e_d 55  NaN 

Mam prawie rozwiązany sposób to zrobić, ale jest jeden problem lewo utknąłem przy ul.

Oto moje rozwiązanie do tej pory:

for i,row in P.iterrows(): 
    P.ix[i,'RowDelta'] = row['AWBW']\ 
    - P[(P['A'] == row.AB[2]) & (P['B'] == row.AB[0])]['AWBW'].get(0,np.nan) 

Problemem jest to, że P[(P['A'] == row.AB[2]) & (P['B'] == row.AB[0])]['AWBW'] powraca cykl, który jest albo pusta lub dokładnie jeden element, którego wskaźnik jest jednak zmienna.

Teraz metoda series.get rozwiązuje problem powrocie NaN gdy seria jest pusty, ale chce ostateczne wartości indeksu, w tym przypadku używam 0, ale nie mogę się tam dostać dynamiczny indeks.

Nie mogę tego zrobić na przykład

T = P[(P['A'] == row.AB[2]) & (P['B'] == row.AB[0])]['AWBW'] 
T.get(T.index[0],np.nan) 

ponieważ nie ma indeksu jeżeli szereg jest pusty, a to prowadzi do błędu, gdy robi T.index[0]. To samo dotyczy moich prób użycia iloc.

Czy istnieje sposób na dynamiczne pobranie nieznanego indeksu szeregu, jeśli ma on jeden element (i nigdy więcej niż jeden), a jednocześnie obsługuje przypadek pustej serii?

+1

Zacznij od scalenia podziału "AB" na odwróconej jednostce. 'AB = P.AB.str.split ('_', expand = True)', po którym następuje 'AB.merge (AB, left_on = [0, 1], right_on = [1, 0])'. – piRSquared

+0

Zrobiłem to, dziękuję. Odpowiem wtedy na moje własne pytanie. – Khris

Odpowiedz

2

zasługa piRSquared dla wskazujące mnie we właściwym kierunku dla rozwiązania:

AB = P.AB.str.split('_', expand=True) 
AB = AB.merge(AB, left_on=[0, 1], right_on=[1, 0],how='inner')[[0,1]] 
AB = AB.merge(P,left_on=[0,1], right_on=['A','B'])[['A','AW','B','BW']] 
AB = AB.merge(P,left_on=['A','B'], right_on=['B','A'])[['AW_x','BW_x','AW_y','BW_y','AB']] 
AB['RowDelta'] = AB.AW_y+AB.BW_y-AB.AW_x-AB.BW_x 
P = P.merge(AB[['AB','RowDelta']],on='AB',how='outer') 

Może to może być wykonany krótszy lub ładniej, ale działa na pewno.

Powiązane problemy