2013-07-21 3 views
17

मैं एक एसक्यूएल पृष्ठभूमि से आते हैं और मैं अक्सर निम्नलिखित डाटा प्रोसेसिंग कदम का उपयोग करें:SQL जैसी पांडा में खिड़की कार्य: अजगर पांडा Dataframe में पंक्ति क्रमांकन

  1. विभाजन एक या अधिक फ़ील्ड
  2. करके डेटा की तालिका
  3. प्रत्येक विभाजन के लिए, अपने पंक्तियों में से प्रत्येक के लिए एक rownumber कि जहां विश्लेषक बढ़ते या घटते निर्दिष्ट करता है एक या अधिक अन्य क्षेत्रों से पंक्ति में शुमार जोड़ने

पूर्व:

df = pd.DataFrame({'key1' : ['a','a','a','b','a'], 
      'data1' : [1,2,2,3,3], 
      'data2' : [1,10,2,3,30]}) 
df 
    data1  data2  key1  
0 1   1   a   
1 2   10  a   
2 2   2   a  
3 3   3   b  
4 3   30  a   

मैं कैसे इस एसक्यूएल खिड़की कार्य करने के लिए पांडा बराबर करने के लिए देख रहा हूँ:

RN = ROW_NUMBER() OVER (PARTITION BY Key1, Key2 ORDER BY Data1 ASC, Data2 DESC) 


    data1  data2  key1 RN 
0 1   1   a  1  
1 2   10  a  2 
2 2   2   a  3 
3 3   3   b  1 
4 3   30  a  4 

मैं काम करने के लिए जहां कोई 'विभाजन' देखते हैं जिसके बाद मैं मिल गया है की कोशिश की है:

def row_number(frame,orderby_columns, orderby_direction,name): 
    frame.sort_index(by = orderby_columns, ascending = orderby_direction, inplace = True) 
    frame[name] = list(xrange(len(frame.index))) 

मैं इस विचार का विस्तार करने के विभाजन (पांडा में समूहों) के साथ काम करने की कोशिश की लेकिन निम्नलिखित काम नहीं किया:

df1 = df.groupby('key1').apply(lambda t: t.sort_index(by=['data1', 'data2'], ascending=[True, False], inplace = True)).reset_index() 

def nf(x): 
    x['rn'] = list(xrange(len(x.index))) 

df1['rn1'] = df1.groupby('key1').apply(nf) 

लेकिन जब मैं ऐसा करता हूं तो मुझे बहुत सारे NaNs मिलते हैं।

आदर्श रूप से, एसक्यूएल की विंडो फ़ंक्शन क्षमता को दोहराने के लिए एक संक्षिप्त तरीका होगा (मैंने खिड़की आधारित समेकित निकाला है ... यह पांडा में एक लाइनर है) ... क्या कोई मेरे साथ साझा कर सकता है पांडास में इस तरह की पंक्तियों की संख्या के लिए सबसे बेवकूफ तरीका?

+0

के लिए पांडा रैंक विधि पर एक नज़र डालें है आप की तरह लगता है चाहिए करने के लिए 'सक्षम होने के लिए एकाधिक कॉलम द्वारा .rank' ... –

उत्तर

8

आप rank विधि के साथ दो बार groupby का उपयोग करके ऐसा कर सकते हैं:

In [11]: g = df.groupby('key1') 

मूल्यों जो एक ही data1 का हिस्सा ही आर.एन. देने के लिए न्यूनतम विधि तर्क का उपयोग करें:

In [12]: g['data1'].rank(method='min') 
Out[12]: 
0 1 
1 2 
2 2 
3 1 
4 4 
dtype: float64 

In [13]: df['RN'] = g['data1'].rank(method='min') 

और फिर इन परिणामों को समूहबद्ध करें और डेटा 2:

In [14]: g1 = df.groupby(['key1', 'RN']) 

In [15]: g1['data2'].rank(ascending=False) - 1 
Out[15]: 
0 0 
1 0 
2 1 
3 0 
4 0 
dtype: float64 

In [16]: df['RN'] += g1['data2'].rank(ascending=False) - 1 

In [17]: df 
Out[17]: 
    data1 data2 key1 RN 
0  1  1 a 1 
1  2  10 a 2 
2  2  2 a 3 
3  3  3 b 1 
4  3  30 a 4 
के संबंध में रैंक जोड़ें

ऐसा लगता है कि ऐसा करने का मूल तरीका होना चाहिए (वहां हो सकता है! ...)।

+0

मैं मानता हूं, कई स्तंभों द्वारा रैंकिंग प्राकृतिक लगता है ... क्या मुझे इसे जिथब पर अनुरोध करना चाहिए? – AllenQ

+0

भी कामकाज के लिए बहुत बहुत धन्यवाद! – AllenQ

+0

@AllenQ पहले से ही https://github.com/pydata/pandas/issues/4311 :) –

-1

pandas.lib.fast_zip() सरणी की सूची से एक ट्यूपल सरणी बना सकता है। आप एक टपल श्रृंखला बनाने के लिए इस सुविधा का उपयोग कर सकते हैं, और फिर इसे रैंक:

values = {'key1' : ['a','a','a','b','a','b'], 
      'data1' : [1,2,2,3,3,3], 
      'data2' : [1,10,2,3,30,20]} 

df = pd.DataFrame(values, index=list("abcdef")) 

def rank_multi_columns(df, cols, **kw): 
    data = [] 
    for col in cols: 
     if col.startswith("-"): 
      flag = -1 
      col = col[1:] 
     else: 
      flag = 1 
     data.append(flag*df[col]) 
    values = pd.lib.fast_zip(data) 
    s = pd.Series(values, index=df.index) 
    return s.rank(**kw) 

rank = df.groupby("key1").apply(lambda df:rank_multi_columns(df, ["data1", "-data2"])) 

print rank 

परिणाम:

a 1 
b 2 
c 3 
d 2 
e 4 
f 1 
dtype: float64 
22

आप भी उपयोग कर सकते हैं sort_values(), groupby() और अंत में cumcount() + 1:

df['RN'] = df.sort_values(['data1','data2'], ascending=[True,False]) \ 
      .groupby(['key1']) \ 
      .cumcount() + 1 
print(df) 

उपज:

data1 data2 key1 RN 
0  1  1 a 1 
1  2  10 a 2 
2  2  2 a 3 
3  3  3 b 1 
4  3  30 a 4 

पीएस पांडा 0 के साथ परीक्षण किया।18

+0

बस इस विधि को आजमाया और निम्न चेतावनी प्राप्त की: SettingWithCopyWarning: एक मान से एक टुकड़ा की प्रति पर सेट करने का प्रयास कर रहा है एक डाटाफ्रेम .loc [row_indexer, col_indexer] = value के बजाय –

+0

@AndrewL का उपयोग करने का प्रयास करें, आपका 'डीएफ' एक "डीएफ के टुकड़े की प्रतिलिपि प्रतिलिपि" प्रतीत होता है ... क्या निम्न आदेश आपके' df' के लिए काम करता है: ' डीएफ ['नया'] = 0' __without__ यह चेतावनी? – MaxU

+0

आपकी अंतर्दृष्टि के लिए धन्यवाद। उपरोक्त आदेश वास्तव में चेतावनी फेंकने के बिना काम करता है। क्या आप समझा सकते हैं कि यह "डीएफ के टुकड़े की प्रति" समस्याग्रस्त है और इसे नियमित डीएफ से अलग तरीके से क्यों संभाला जाता है? धन्यवाद! –

0

आप transform उपयोग कर सकते हैं और Rank एक साथ यहाँ एक उदाहरण

df = pd.DataFrame({'C1' : ['a','a','a','b','b'], 
      'C2' : [1,2,3,4,5]}) 
df['Rank'] = df.groupby(by=['C1'])['C2'].transform(lambda x: x.rank()) 
df 

enter image description here

अधिक जानकारी

संबंधित मुद्दे