본문 바로가기
통계프로그램 비교 시리즈/프로그래밍비교(Oracle,Python,R,SAS)

[데이터 추출] 상위 Top 5 관측치 추출하기 - 106

by 기서무나구물 2022. 10. 3.

포스팅 목차

     

    106. Find out the top 5 earner of company

     

    * 최대 급여 수령자 상위 5명의 정보를 출력하시오.


    • Oracle : ROW_NUMBER()
    • 파이썬 Pandas : nlargest()
    • R 프로그래밍 : order(), row_number()
    • R Dplyr Package : slice_max(), top_n()
    • R sqldf Package : ROW_NUMBER(), RANK()
    • Python pandasql Package : ROW_NUMBER(), RANK()
    • R data.table Package : order()
    • SAS Proc SQL : monotonic()
    • SAS Data Step : PROC RANK, N
    • Python Dfply Package : row_number(), min_rank()
    • 파이썬 Base 프로그래밍 :

     


    1. Oracle(오라클)

    개별 관측치를 기준으로 본인 급여보다 더 많은 급여를 수령하는 직원의 수를 카운트하여서 상위 5명의 정보를 출력한다.

     

    Oracle Programming
    select * 
    from   emp e 
    where  5 > (select count(*) from emp where sal > e.sal) 
    order 
       by  sal desc;

     


    Row_number() 함수

     

    Oracle Programming
    select *
    from   ( select a.*, ROW_NUMBER() OVER(ORDER BY sal desc) AS row_num from emp a)
    where  row_num <= 5

     

     


    2. Python Pandas(파이썬)

    nlargest 함수를 사용하여서 emp 테이블에서 상위 급여 수령자 5명의 정보를 선택한다.

     

    Python Programming
    emp.nlargest(5, 'sal')

     


    Results
    empno ename job mgr hiredate sal comm deptno
    7839 KING PRESIDENT NaN 1981/11/17 5000 NaN 10
    7788 SCOTT ANALYST 7566.0 1982/12/09 3000 NaN 20
    7902 FORD ANALYST 7566.0 1981/12/03 3000 NaN 20
    7566 JONES MANAGER 7839.0 1981/04/02 2975 NaN 20
    7698 BLAKE MANAGER 7839.0 1981/03/01 2850 NaN 30

     

     


    3. R Programming (R Package)

    emp 테이블을 급여를 기준으로 내림차순으로 정렬 후 상위 급여 수령자 5명의 정보를 선택한다.

     

    R Programming
    %%R
    
    emp[order(-emp$sal),][1:5, ]

     

    Results
    # A tibble: 5 x 8
      empno ename job         mgr hiredate     sal  comm deptno
      <dbl> <chr> <chr>     <dbl> <date>     <dbl> <dbl>  <dbl>
    1  7839 KING  PRESIDENT    NA 1981-11-17  5000    NA     10
    2  7788 SCOTT ANALYST    7566 1982-12-09  3000    NA     20
    3  7902 FORD  ANALYST    7566 1981-12-03  3000    NA     20
    4  7566 JONES MANAGER    7839 1981-04-02  2975    NA     20
    5  7698 BLAKE MANAGER    7839 1981-03-01  2850    NA     30

     


    row_number 함수를 사용하여서 emp 테이블을 급여를 기준으로 내림차순으로 정렬 후 상위 급여 수령자 5명의 정보를 선택한다.

     

    R Programming
    %%R
    
    filter(emp, row_number(desc(sal)) <= 5)

     

    Results
    # A tibble: 5 x 8
      empno ename job         mgr hiredate     sal  comm deptno
      <dbl> <chr> <chr>     <dbl> <date>     <dbl> <dbl>  <dbl>
    1  7566 JONES MANAGER    7839 1981-04-02  2975    NA     20
    2  7698 BLAKE MANAGER    7839 1981-03-01  2850    NA     30
    3  7788 SCOTT ANALYST    7566 1982-12-09  3000    NA     20
    4  7839 KING  PRESIDENT    NA 1981-11-17  5000    NA     10
    5  7902 FORD  ANALYST    7566 1981-12-03  3000    NA     20

     

     


    4. R Dplyr Package

    slice_max 함수를 사용하여서 emp 테이블을 급여를 기준으로 상위 급여 수령자 5명의 정보를 선택한다.

     

    R Programming
    %%R
    
    emp %>% 
      slice_max(sal, n = 5)

     

    Results
    # A tibble: 5 x 8
      empno ename job         mgr hiredate     sal  comm deptno
      <dbl> <chr> <chr>     <dbl> <date>     <dbl> <dbl>  <dbl>
    1  7839 KING  PRESIDENT    NA 1981-11-17  5000    NA     10
    2  7788 SCOTT ANALYST    7566 1982-12-09  3000    NA     20
    3  7902 FORD  ANALYST    7566 1981-12-03  3000    NA     20
    4  7566 JONES MANAGER    7839 1981-04-02  2975    NA     20
    5  7698 BLAKE MANAGER    7839 1981-03-01  2850    NA     30

     


    top_n 함수를 사용하여서 emp 테이블을 급여를 기준으로 상위 급여 수령자 5명의 정보를 선택한 후에 arrange 함수를 사용하여서 내림차순으로 정렬한다.

     

    R Programming
    %%R
    
    emp %>% 
      top_n(5, sal) %>%
      arrange(desc(sal))

     

    Results
    # A tibble: 5 x 8
      empno ename job         mgr hiredate     sal  comm deptno
      <dbl> <chr> <chr>     <dbl> <date>     <dbl> <dbl>  <dbl>
    1  7566 JONES MANAGER    7839 1981-04-02  2975    NA     20
    2  7698 BLAKE MANAGER    7839 1981-03-01  2850    NA     30
    3  7788 SCOTT ANALYST    7566 1982-12-09  3000    NA     20
    4  7839 KING  PRESIDENT    NA 1981-11-17  5000    NA     10
    5  7902 FORD  ANALYST    7566 1981-12-03  3000    NA     20

     

     


    5. R sqldf Package

    개별 관측치를 기준으로 본인 급여보다 더 많은 급여를 수령하는 직원의 수를 카운트하여서 상위 5명의 정보를 출력한다.

     

    R Programming
    %%R
    
    sqldf(" select *
            from   emp e 
            where  5 > (select count(*) from emp where sal>e.sal) 
            order 
               by  sal desc;")

     

    Results
      empno ename       job  mgr   hiredate  sal comm deptno
    1  7839  KING PRESIDENT   NA 1981-11-17 5000   NA     10
    2  7788 SCOTT   ANALYST 7566 1982-12-09 3000   NA     20
    3  7902  FORD   ANALYST 7566 1981-12-03 3000   NA     20
    4  7566 JONES   MANAGER 7839 1981-04-02 2975   NA     20
    5  7698 BLAKE   MANAGER 7839 1981-03-01 2850   NA     30

     


    위 예제의 서브쿼리가 반환하는 값을 살펴보면 본인의 급여보다 더 많은 급여를 수려하는 직원을 카운트한다.

     

    R Programming
    %%R
    
    sqldf(" select (select count(*) from emp where sal>e.sal) upper_emp,
                   e.*
            from   emp e
            order 
               by  sal desc;") %>% head(7)

     

    Results
      upper_emp empno ename       job  mgr   hiredate  sal comm deptno
    1         0  7839  KING PRESIDENT   NA 1981-11-17 5000   NA     10
    2         1  7788 SCOTT   ANALYST 7566 1982-12-09 3000   NA     20
    3         1  7902  FORD   ANALYST 7566 1981-12-03 3000   NA     20
    4         3  7566 JONES   MANAGER 7839 1981-04-02 2975   NA     20
    5         4  7698 BLAKE   MANAGER 7839 1981-03-01 2850   NA     30
    6         5  7782 CLARK   MANAGER 7839 1981-01-09 2450   NA     10
    7         6  7499 ALLEN  SALESMAN 7698 1981-02-20 1600  300     30

     


    개별 관측치를 기준으로 본인 급여보다 더 많은 급여를 수령하는 직원의 수를 카운트하여서 상위 5명을 선택 후 emp 테이블에서 해당 사원 정보를 추출한다.

     

    R Programming
    %%R
    
    sqldf("select a.*                                   \
           from   emp a,                                \
                  ( select a.EMPNO,                     \
                           a.sal,                       \
                           count(distinct b.EMPNO) cnt  \
                    from   emp a                        \
                           left join emp b              \
                                on a.sal < b.sal        \
                    group by                            \
                           a.EMPNO,                     \
                           a.sal                        \
                    having count(*) < 5                 \
                    ) b                                 \
           where  a.empno = b.empno                     \
             and  a.sal   = b.sal;")

     

    Results
      empno ename       job  mgr   hiredate  sal comm deptno
    1  7566 JONES   MANAGER 7839 1981-04-02 2975   NA     20
    2  7698 BLAKE   MANAGER 7839 1981-03-01 2850   NA     30
    3  7788 SCOTT   ANALYST 7566 1982-12-09 3000   NA     20
    4  7839  KING PRESIDENT   NA 1981-11-17 5000   NA     10
    5  7902  FORD   ANALYST 7566 1981-12-03 3000   NA     20

     


    ROW_NUMBER() 함수를 사용하여서 emp 테이블을 급여를 기준으로 내림차순으로 정렬 후 급여 상위 부터 조회 순번을 부여한 후에 상위 급여 수령자 5명의 정보를 선택한다.

     

    R Programming
    %%R
    
    sqldf("select *
           from   ( select *, ROW_NUMBER() OVER(ORDER BY sal desc) AS row_num from emp )
           where  row_num <= 5")

     

    Results
      empno ename       job  mgr   hiredate  sal comm deptno row_num
    1  7839  KING PRESIDENT   NA 1981-11-17 5000   NA     10       1
    2  7788 SCOTT   ANALYST 7566 1982-12-09 3000   NA     20       2
    3  7902  FORD   ANALYST 7566 1981-12-03 3000   NA     20       3
    4  7566 JONES   MANAGER 7839 1981-04-02 2975   NA     20       4
    5  7698 BLAKE   MANAGER 7839 1981-03-01 2850   NA     30       5

     


    Rank() 함수를 사용하여서 emp 테이블을 급여를 기준으로 내림차순으로 정렬 후 급여 상위 부터 조회 순번을 부여한 후에 상위 급여 수령자 5명의 정보를 선택한다.

     

    R Programming
    %%R
    
    sqldf("select *
           from   ( select *, RANK() OVER(ORDER BY sal desc) AS row_rank from emp )
           where  row_rank <= 5")

     

    Results
      empno ename       job  mgr   hiredate  sal comm deptno row_rank
    1  7839  KING PRESIDENT   NA 1981-11-17 5000   NA     10        1
    2  7788 SCOTT   ANALYST 7566 1982-12-09 3000   NA     20        2
    3  7902  FORD   ANALYST 7566 1981-12-03 3000   NA     20        2
    4  7566 JONES   MANAGER 7839 1981-04-02 2975   NA     20        4
    5  7698 BLAKE   MANAGER 7839 1981-03-01 2850   NA     30        5

     

     


    6. Python pandasql Package

     

    Count() 함수

     

    Python Programming
    ps.sqldf("select * from emp e where 5 > (select count(*) from emp where sal>e.sal) order by sal desc;")

     

    Results
    empno ename job mgr hiredate sal comm deptno
    7839 KING PRESIDENT NaN 1981/11/17 5000 None 10
    7788 SCOTT ANALYST 7566.0 1982/12/09 3000 None 20
    7902 FORD ANALYST 7566.0 1981/12/03 3000 None 20
    7566 JONES MANAGER 7839.0 1981/04/02 2975 None 20
    7698 BLAKE MANAGER 7839.0 1981/03/01 2850 None 30

     


     

    Python Programming
    ps.sqldf("select * from (select (select count(*) from emp where sal>e.sal) as row_rank,* from emp e ) where row_rank <5 order by sal desc")

     


    Results
    row_rank empno ename job mgr hiredate sal comm deptno
    0 7839 KING PRESIDENT NaN 1981/11/17 5000 None 10
    1 7788 SCOTT ANALYST 7566.0 1982/12/09 3000 None 20
    1 7902 FORD ANALYST 7566.0 1981/12/03 3000 None 20
    3 7566 JONES MANAGER 7839.0 1981/04/02 2975 None 20
    4 7698 BLAKE MANAGER 7839.0 1981/03/01 2850 None 30

     


     

    Python Programming
    ps.sqldf("select a.sal,                \
                     count(*) cnt          \
              from   emp a                 \
                     left join emp b       \
                          on a.sal < b.sal \
              group by                     \
                     a.sal                 \
              having count(*) <= 5")

     


    Results
    sal cnt
    2450 5
    2850 4
    2975 3
    3000 2
    5000 1

     

     


    7. R data.table Package

    emp 테이블을 급여를 기준으로 내림차순으로 정렬 후 상위 급여 수령자 5명의 정보를 선택한다.

     

    R Programming
    %%R
    
    DT          <- data.table(emp)
    dept_DT     <- data.table(dept)
    salgrade_DT <- data.table(salgrade)
    
    DT[order(-DT$sal),][1:5, ]

     

    Results
       empno ename       job  mgr   hiredate  sal comm deptno
    1:  7839  KING PRESIDENT   NA 1981-11-17 5000   NA     10
    2:  7788 SCOTT   ANALYST 7566 1982-12-09 3000   NA     20
    3:  7902  FORD   ANALYST 7566 1981-12-03 3000   NA     20
    4:  7566 JONES   MANAGER 7839 1981-04-02 2975   NA     20
    5:  7698 BLAKE   MANAGER 7839 1981-03-01 2850   NA     30

     

     


    8. SAS Proc SQL

    개별 관측치를 기준으로 본인 급여보다 더 많은 급여를 수령하는 직원의 수를 카운트하여서 상위 5명의 정보를 출력한다.

     

    SAS Programming
    %%SAS sas
    
    PROC SQL;
      CREATE TABLE STATSAS_1 AS
        select * 
        from   emp e 
        where  5 > (select count(*) from emp where sal > e.sal) order by sal desc;
    QUIT;
    PROC PRINT;RUN;

     


    Results
    empno ename job mgr hiredate sal comm deptno
    7839 KING PRESIDEN . 1981-11-17 5000 . 10
    7788 SCOTT ANALYST 7566 1982-12-09 3000 . 20
    7902 FORD ANALYST 7566 1981-12-03 3000 . 20
    7566 JONES MANAGER 7839 1981-04-02 2975 . 20
    7698 BLAKE MANAGER 7839 1981-03-01 2850 . 30

     


     

    SAS Programming
    %%SAS sas
    
    PROC SQL;
      CREATE TABLE STATSAS_2 AS
        select a.*
           from   emp a,
                  ( select a.EMPNO,
                           a.sal,
                           count(distinct b.EMPNO) as cnt
                    from   emp a
                           left join emp b
                                on a.sal < b.sal
                    group by
                           a.EMPNO,
                           a.sal
                    having count(*) < 5
                    ) b
           where  a.empno = b.empno
             and  a.sal   = b.sal;
    QUIT;
    PROC PRINT;RUN;

     


    Results
    empno ename job mgr hiredate sal comm deptno
    7566 JONES MANAGER 7839 1981-04-02 2975 . 20
    7698 BLAKE MANAGER 7839 1981-03-01 2850 . 30
    7788 SCOTT ANALYST 7566 1982-12-09 3000 . 20
    7839 KING PRESIDEN . 1981-11-17 5000 . 10
    7902 FORD ANALYST 7566 1981-12-03 3000 . 20

     


    • SAS에서는 인라인뷰에서 ORDER BY를 사용하지 못하는 단점이 있음;
    • 사전 정렬 후 monotonic() 사용;
    • 통계분석연구회 카페;
    • PROC SQL에서 중복제거는 일반적으로 SUBQUERY나 JOIN 으로 일반적으로 처리하지만, MONOTONIC() 함수로 처리해보았습니다;
    • MONOTONIC은 메모리에서 처리 순서에 따라서 씨퀀스 방식이 달라지므로 권해드리는 방식은 아님을 알려드립니다;
    • PROC SQL에서 MONOTONIC은 정식 지원 옵션은 아님;
    • http://support.sas.com/kb/15/138.html;
    • Usage Note 15138: Support for the MONOTONIC() function in PROC SQL;
    • [ 참고 ]

          - 데이터 중복제거(first. / last대안) - MAX , MIN : http://cafe.daum.net/statsas/3F8j/162

          - [SQL] PROC SQL에서 nodupkye 사용(monotonic) : http://cafe.daum.net/statsas/3F8j/70

          - [MAX] 변수중에 2번째 큰값 찾기 http://cafe.daum.net/statsas/3F8j/163;

    • 사전 소팅 필수;
    SAS Programming
    %%SAS sas
    
    PROC SQL;
      CREATE TABLE STATSAS_3 AS
        select e.*
        from   emp e 
        order 
           by  sal desc;
    
      create table STATSAS_4 as 
        select a.*, 
               monotonic() as sal_rank
        from   STATSAS_3 a
        HAVING sal_rank<=5;  * HAVING CALCULATED sal_rank<=5;
    QUIT;
    PROC PRINT;RUN;

     


    Results
    empno ename job mgr hiredate sal comm deptno sal_rank
    7839 KING PRESIDEN . 1981-11-17 5000 . 10 1
    7902 FORD ANALYST 7566 1981-12-03 3000 . 20 2
    7788 SCOTT ANALYST 7566 1982-12-09 3000 . 20 3
    7566 JONES MANAGER 7839 1981-04-02 2975 . 20 4
    7698 BLAKE MANAGER 7839 1981-03-01 2850 . 30 5

     


     

    SAS Programming
    %%SAS sas
    
    proc sql;
      create table STATSAS_4(where=(monotonic()<=5)) as
        select e.*
        from   emp e 
        order 
           by  sal desc;
    quit;
    PROC PRINT;RUN;

     


    Results
    empno ename job mgr hiredate sal comm deptno
    7839 KING PRESIDEN . 1981-11-17 5000 . 10
    7902 FORD ANALYST 7566 1981-12-03 3000 . 20
    7788 SCOTT ANALYST 7566 1982-12-09 3000 . 20
    7566 JONES MANAGER 7839 1981-04-02 2975 . 20
    7698 BLAKE MANAGER 7839 1981-03-01 2850 . 30

     


     

    SAS Programming
    %%SAS sas
    
    proc sql;
        select 1,
               EMPNO,
               SAL,
               monotonic() As row_numb ,
               min(calculated row_numb) as indicator
         from EMP
         group by 1
         ORDER BY 3;
    quit;

     

     
    Results
      empno sal row_numb indicator
    1 7369 800 1 1
    1 7900 950 12 1
    1 7876 1100 11 1
    1 7654 1250 5 1
    1 7521 1250 3 1
    1 7934 1300 14 1
    1 7844 1500 10 1
    1 7499 1600 2 1
    1 7782 2450 7 1
    1 7698 2850 6 1
    1 7566 2975 4 1
    1 7902 3000 13 1
    1 7788 3000 8 1
    1 7839 5000 9 1

     


    [참고] 올림차순

     

    SAS Programming
    %%SAS sas
    
    PROC SQL;
      CREATE TABLE STATSAS_5 AS
        SELECT A.empno,
               A.ename,
               A.sal,
               COUNT(B.empno)+1 AS RANK
        FROM   EMP A
               LEFT JOIN EMP B
                    ON  A.SAL  > B.sal
        GROUP BY
               A.empno,
               A.ename,
               A.sal
        HAVING RANK<=5;
    QUIT;
    PROC PRINT;RUN;

     


    Results
    empno ename sal RANK
    7369 SMITH 800 1
    7521 WARD 1250 4
    7654 MARTIN 1250 4
    7876 ADAMS 1100 3
    7900 JAMES 950 2

     

     


    9. SAS Data Step

     

    RANK 프로시져 사용;

     

    SAS Programming
    %%SAS sas
    PROC RANK DATA=EMP OUT=STATSAS_6(WHERE=(RANK<=5)) DESCENDING;
         RANKS RANK;
         VAR SAL ;
    RUN;
    PROC PRINT;RUN;

     


    Results
    empno ename job mgr hiredate sal comm deptno RANK
    7566 JONES MANAGER 7839 1981-04-02 2975 . 20 4.0
    7698 BLAKE MANAGER 7839 1981-03-01 2850 . 30 5.0
    7788 SCOTT ANALYST 7566 1982-12-09 3000 . 20 2.5
    7839 KING PRESIDEN . 1981-11-17 5000 . 10 1.0
    7902 FORD ANALYST 7566 1981-12-03 3000 . 20 2.5

     


    SAS Programming
    %%SAS sas
    
    PROC SORT DATA=EMP OUT=EMP_1;
         BY DESCENDING SAL;
    RUN;
    DATA STATSAS_7;
     SET EMP_1;
         BY DESCENDING SAL;
         IF _N_ <=5;
    RUN;
    PROC PRINT;RUN;

     


    Results
    empno ename job mgr hiredate sal comm deptno
    7839 KING PRESIDEN . 1981-11-17 5000 . 10
    7788 SCOTT ANALYST 7566 1982-12-09 3000 . 20
    7902 FORD ANALYST 7566 1981-12-03 3000 . 20
    7566 JONES MANAGER 7839 1981-04-02 2975 . 20
    7698 BLAKE MANAGER 7839 1981-03-01 2850 . 30

     


     

    SAS Programming
    %%SAS sas
    
    PROC SORT DATA=EMP OUT=EMP_1;
         BY DESCENDING SAL;
    RUN;
    DATA STATSAS_8;
     SET EMP_1;
         BY DESCENDING SAL;
         RANK + 1;
         IF RANK <=5;
    RUN;
    
    PROC PRINT;RUN;

     


    Results
    empno ename job mgr hiredate sal comm deptno RANK
    7839 KING PRESIDEN . 1981-11-17 5000 . 10 1
    7788 SCOTT ANALYST 7566 1982-12-09 3000 . 20 2
    7902 FORD ANALYST 7566 1981-12-03 3000 . 20 3
    7566 JONES MANAGER 7839 1981-04-02 2975 . 20 4
    7698 BLAKE MANAGER 7839 1981-03-01 2850 . 30 5

     

     


    10. Python Dfply Package

     

    row_number() 함수

     

    Python Programming
    emp >> mutate(row_rank=row_number(X.sal, ascending=False)) >> filter_by(X.row_rank <= 5) >> arrange(~X.sal)

     


    Results
    empno ename job mgr hiredate sal comm deptno row_rank
    7839 KING PRESIDENT NaN 1981/11/17 5000 NaN 10 1.0
    7788 SCOTT ANALYST 7566.0 1982/12/09 3000 NaN 20 2.0
    7902 FORD ANALYST 7566.0 1981/12/03 3000 NaN 20 3.0
    7566 JONES MANAGER 7839.0 1981/04/02 2975 NaN 20 4.0
    7698 BLAKE MANAGER 7839.0 1981/03/01 2850 NaN 30 5.0

     


    min_rank() 함수

     

    Python Programming
    emp >> mutate(row_rank=min_rank(X.sal, ascending=False)) >> filter_by(X.row_rank <= 5) >> arrange(~X.sal)

     


    Results
    empno ename job mgr hiredate sal comm deptno row_rank
    7839 KING PRESIDENT NaN 1981/11/17 5000 NaN 10 1.0
    7788 SCOTT ANALYST 7566.0 1982/12/09 3000 NaN 20 2.0
    7902 FORD ANALYST 7566.0 1981/12/03 3000 NaN 20 2.0
    7566 JONES MANAGER 7839.0 1981/04/02 2975 NaN 20 4.0
    7698 BLAKE MANAGER 7839.0 1981/03/01 2850 NaN 30 5.0

     


    [SQL, Pandas, R Prog, Dplyr, SQLDF, PANDASQL, DATA.TABLE]   SQL EMP 예제로 만나는 테이블 데이터 전처리 방법 리스트

    반응형

    댓글