복붙노트

[PYTHON] PANDAS의 SQL과 유사한 창 기능 : Python Pandas Dataframe의 행 번호 매기기

PYTHON

PANDAS의 SQL과 유사한 창 기능 : Python Pandas Dataframe의 행 번호 매기기

나는 SQL 배경에서 왔고 다음 데이터 처리 단계를 자주 사용합니다.

전의:

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        

나는 PANDAS를이 SQL 창 함수와 동등하게 수행하는 방법을 찾고있다.

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)

하지만이 작업을 수행 할 때 많은 NaN이 생겼습니다.

이상적으로, sql의 창 함수 기능을 복제하는 간결한 방법이 있습니다. (창 기반 집계를 알아 냈습니다 ... 판다에있는 하나의 라이너입니다.) 누군가가 나에게 가장 관용적 인 방법을 공유 할 수 있습니까? PANDAS에서 이처럼 숫자 행을?

해결법

  1. ==============================

    1.rankby 메서드와 함께 groupby를 두 번 사용하여이 작업을 수행 할 수 있습니다.

    rankby 메서드와 함께 groupby를 두 번 사용하여이 작업을 수행 할 수 있습니다.

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

    동일한 데이터를 공유하는 값을 동일한 RN에 부여하려면 min 메소드 인수를 사용하십시오.

    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')
    

    그런 다음 이들 결과를 그룹화하여 data2와 관련하여 순위를 추가하십시오.

    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
    

    이 작업을 수행하는 기본 방법이되어야하는 것처럼 느껴집니다 (잘 될 수도 있습니다! ...).

  2. ==============================

    2.당신은 또한 sort_values ​​(), groupby () 그리고 마지막으로 cumcount () + 1 :

    당신은 또한 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로 테스트 한 PS

  3. ==============================

    3.transform과 rank를 함께 사용할 수 있습니다. 예제가 있습니다.

    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
    

    자세한 정보는 Pandas Rank 방법을 살펴보십시오.

  4. ==============================

    4.pandas.lib.fast_zip ()은 배열리스트로부터 튜플 배열을 생성 할 수 있습니다. 이 함수를 사용하여 튜플 시리즈를 만든 다음 순위를 매길 수 있습니다.

    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
    
  5. from https://stackoverflow.com/questions/17775935/sql-like-window-functions-in-pandas-row-numbering-in-python-pandas-dataframe by cc-by-sa and MIT license