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

[날짜 함수] 특정 조건에 따라 해당 날짜 반환 - 148 (오라클 SQL, R, Python, SAS)

by 기서무나구물 2023. 1. 3.

포스팅 목차

    148. Employees hire on 15th of any month are paid on the last Friday of that month. Those hired after the 15th are paid on the last Friday of the following month. Print a list of employees, their hiredate and first pay date. Sort on day of hiredate

     

    * 15일 이전에 입사한 직원은 해당월의 마지막 금요일에 급여가 지급되고, 15일 이후에 입사한 직원은 다음 달 마지막 금요일에 급여가 지급된다. 직원들의 입사일자와 입사 후 첫 번째 지급된 급여일자를 출력하고, 입사일자의 일자를 기준으로 정렬하시오


    • Oracle : CASE WHEN 조건문, TO_CHAR(), NEXT_DAY(), LAST_DAY(), ADD_months()
    • 파이썬 Pandas : pd.to_datetime(), MonthEnd(), Day(), Week(), pd.DateOffset(), apply(), Lambda 함수, IF 조건문, DT.date.today(), REL.relativedelta(), apply(), relativedelta()
    • R 프로그래밍 : apply(), vapply(), sapply(), 사용자 함수 생성, lubridate::ceiling_date(), lubridate::rollback(), class(), base::ifelse 조건문, day(), ifelse() 조건문, lubridate::ceiling_date(), data.table::fifelse() 조건문
    • R Dplyr Package : dplyr::if_else() 조건문, ceiling_date(), rollback()
    • R sqldf Package : strftime(), datetime(), date(), Case When 조건문
    • Python pandasql Package : strftime(), datetime(), date(), Case When 조건문
    • R data.table Package : dplyr::if_else() 조건문, data.table::fifelse() 조건문, ceiling_date(), rollback()
    • SAS Proc SQL : intnx(), day(), case when 조건문
    • SAS Data Step : day(), intnx() 함수, IF 조건문
    • Python Dfply Package : make_symbolic(), pd.to_datetime(), MonthEnd(), Day(), pd.DateOffset()
    • 파이썬 Base 프로그래밍 :

     


    1. Oracle(오라클)

    입사일자에서 일자 부분을 추출하여서 15일 이전이면 당월 마지막 금요일의 일자를 산출하고, 15일 이후이면 다음 달 마지막 금요일의 일자를 산출한다.

     

    Oracle Programming
    SELECT ENAME, HIREDATE,
           CASE WHEN TO_CHAR(hiredate,'DD')<=15
                THEN NEXT_DAY(LAST_DAY(hiredate)-7,'friday')
           ELSE NEXT_DAY(LAST_DAY(ADD_months(hiredate,1))-7,'friday') END "payDATE"
    FROM EMP
    order by substr(HIREDATE,7,2);

     


    2. Python Pandas(파이썬)

     

    [참고] 일정 일자 경과 후 일자와 요일 반환하기

    • last_day : pandas.tseries.offsets.MonthEnd 함수를 사용하여서 당월의 마지막 일자를 반환한다.
    • before_day : 7*Day() 함수를 사용하여서 당월 마지막 일자를 기준으로 1주일 이전 날짜를 반환한다.
    • week_day_1 : pd.DateOffset(weekday=FR(0)) 함수를 사용하여서 당월 마지막 금요일의 일자를 반환한다. ( MonthEnd(1) - 7*Day() )가 당월 마지막 일자 1주일 이전 날짜를 반환하고, 이후 금요일 일자를 반환한다.
    • week_day_2 : 1 * Week(weekday=4) 함수를 사용하여서 당월 마지막 금요일의 일자를 반환한다. ( MonthEnd(1) - 7*Day() )가 당월 마지막 일자 1주일 이전 날짜를 반환하고, 이후 금요일 일자를 반환한다.
    • Next_day_1 : pd.DateOffset(months=1) 함수를 사용하여서 입사일자의 다음달 동일한 일자를 계산하고, (MonthEnd(1) - 7*Day() + pd.DateOffset(weekday=FR(0))) 함수를 사용하여서 다음달 마지막 금요일의 일자를 산출한다.
    • Next_day_2 : pd.DateOffset(months=1) 함수를 사용하여서 입사일자의 다음달 동일한 일자를 계산하고, ( MonthEnd(1) - 7Day() + 1Week(weekday=4 ) 함수를 사용하여서 다음달 마지막 금요일의 일자를 산출한다.

     

    Python Programming
    from pandas.tseries.offsets import Day,Week,MonthEnd
    from dateutil.relativedelta import TH
    from dateutil.relativedelta import FR
    import copy
    
    withmooc =copy.copy(emp)
    
    withmooc['last_day']    = pd.to_datetime(withmooc['hiredate'], format="%Y/%m") + MonthEnd(1)
    withmooc['before_day']  = pd.to_datetime(withmooc['hiredate'], format="%Y/%m") + MonthEnd(1) - 7*Day()
    withmooc['week_day_1']  = pd.to_datetime(withmooc['hiredate'], format="%Y/%m") + MonthEnd(1) - 7*Day() + pd.DateOffset(weekday=FR(0))  # 경고메시지(PerformanceWarning)가 출력 됨
    withmooc['week_day_2']  = pd.to_datetime(withmooc['hiredate'], format="%Y/%m") + MonthEnd(1) - 7*Day() + 1*Week(weekday=4) # 4: 금요일
    
    withmooc['Next_day_1']  = pd.to_datetime(withmooc['hiredate'], format="%Y/%m") + pd.DateOffset(months=1)+ MonthEnd(1) - 7*Day() + pd.DateOffset(weekday=FR(0))  # 경고메시지(PerformanceWarning)가 출력 됨
    withmooc['Next_day_2']  = pd.to_datetime(withmooc['hiredate'], format="%Y/%m") + pd.DateOffset(months=1)+ MonthEnd(1) - 7*Day() + 1*Week(weekday=4)             # 4: 금요일
    
    withmooc[['empno','hiredate','last_day','before_day','week_day_1','week_day_2','Next_day_1','Next_day_2']].head(7)

     

    Results
    C:\Users\BACK\anaconda3\lib\site-packages\pandas\core\arrays\datetimes.py:691: PerformanceWarning: Non-vectorized DateOffset being applied to Series or DatetimeIndex
      warnings.warn(

     


      empno hiredate last_day before_day week_day_1 week_day_2 Next_day_1 Next_day_2
    0 7369 1980/12/17 1980-12-31 1980-12-24 1980-12-26 1980-12-26 1981-01-30 1981-01-30
    1 7499 1981/02/20 1981-02-28 1981-02-21 1981-02-27 1981-02-27 1981-03-27 1981-03-27
    2 7521 1981/02/22 1981-02-28 1981-02-21 1981-02-27 1981-02-27 1981-03-27 1981-03-27
    3 7566 1981/04/02 1981-04-30 1981-04-23 1981-04-24 1981-04-24 1981-05-29 1981-05-29
    4 7654 1981/09/28 1981-09-30 1981-09-23 1981-09-25 1981-09-25 1981-10-30 1981-10-30
    5 7698 1981/03/01 1981-03-31 1981-03-24 1981-03-27 1981-03-27 1981-04-24 1981-04-24
    6 7782 1981/01/09 1981-01-31 1981-01-24 1981-01-30 1981-01-30 1981-02-27 1981-02-27

     


    [정답-1] pandas.tseries.offsets 과 lambda 방식 : Week(weekday=4) 함수 사용

    입사일자에서 일자(day) 부분을 추출하여서 15일 이전이면 당월 마지막 금요일의 일자를 산출하고, 15일 이후이면 다음 달 마지막 금요일의 일자를 산출한다.

     

    Python Programming
    from pandas.tseries.offsets import Day,Week,MonthEnd
    import copy
    
    withmooc =copy.copy(emp)
    
    withmooc['payDATE'] = withmooc.apply(lambda row : pd.to_datetime(row['hiredate'], format="%Y/%m") + MonthEnd(1) - 6*Day() + 0*Week(weekday=4)   # 4: 금요일
                                                       if pd.to_datetime(row['hiredate']).day <= 15 
                                                       else pd.to_datetime(row['hiredate'], format="%Y/%m") + MonthEnd(2) - 6*Day() + 0*Week(weekday=4),
                                         axis=1)
    
    withmooc[['empno','hiredate','payDATE']].head(7)

     


    Results
      empno hiredate payDATE
    0 7369 1980/12/17 1981-01-30
    1 7499 1981/02/20 1981-03-27
    2 7521 1981/02/22 1981-03-27
    3 7566 1981/04/02 1981-04-24
    4 7654 1981/09/28 1981-10-30
    5 7698 1981/03/01 1981-03-27
    6 7782 1981/01/09 1981-01-30

     


    [참고] relativedelta

    : 현재일자(‘today’)와 현재일자 이후 가장 빠른 금요일의 날짜(‘next_friday’)를 반환한다.

    Python Programming
    import datetime as DT
    import dateutil.relativedelta as REL
    today = DT.date.today()
    print(today)
    
    rd = REL.relativedelta(days=1, weekday=REL.FR)
    next_friday = today + rd
    print(next_friday)

     

    Results
    2021-04-01
    2021-04-02

     


    [정답-2] lambda 함수 방식 : weekday=FR(0) 함수 사용

     

    입사일자(‘hiredate’)에서 일자(day) 부분을 추출하여서 15일 이전이면 당월 마지막 금요일의 일자를 산출하고, 15일 이후이면 다음 달 마지막 금요일의 일자를 산출한다.

     

    Python Programming
    from dateutil.relativedelta import relativedelta, FR
    
    import copy
    
    withmooc =copy.copy(emp)
    
    withmooc['payDATE'] = withmooc.apply(lambda row: pd.to_datetime(row['hiredate'], format='%Y %m %d') + relativedelta(day=31, days=-6, weekday=FR(0))
                                                   if pd.to_datetime(row['hiredate']).day <= 15 
                                                   else pd.to_datetime(row['hiredate'], format='%Y %m %d') + relativedelta(months=1, day=31, days=-6, weekday=FR(0)),
                                      axis=1 ) 
    
    withmooc.head(7)

     

    Results
      empno ename job mgr hiredate sal comm deptno payDATE
    0 7369 SMITH CLERK 7902.0 1980/12/17 800 NaN 20 1981-01-30
    1 7499 ALLEN SALESMAN 7698.0 1981/02/20 1600 300.0 30 1981-03-27
    2 7521 WARD SALESMAN 7698.0 1981/02/22 1250 500.0 30 1981-03-27
    3 7566 JONES MANAGER 7839.0 1981/04/02 2975 NaN 20 1981-04-24
    4 7654 MARTIN SALESMAN 7698.0 1981/09/28 1250 1400.0 30 1981-10-30
    5 7698 BLAKE MANAGER 7839.0 1981/03/01 2850 NaN 30 1981-03-27
    6 7782 CLARK MANAGER 7839.0 1981/01/09 2450 NaN 10 1981-01-30

     


    [정답] 조건문 - relativedelta과 List comprehension 방식 : weekday=FR(0) 함수 사용

    입사일자(‘hiredate’)에서 일자(day) 부분을 추출하여서 15일 이전이면 당월 마지막 금요일의 일자를 산출하고, 15일 이후이면 다음 달 마지막 금요일의 일자를 산출한다.

     

    Python Programming
    from dateutil.relativedelta import relativedelta, FR
    import copy
    
    withmooc =copy.copy(emp)
    
    withmooc['payDATE'] = [pd.to_datetime(x, format='%Y %m %d') + relativedelta(day=31, days=-6, weekday=FR(0)) 
                           if pd.to_datetime(x).day <= 15 
                           else pd.to_datetime(x, format='%Y %m %d') + relativedelta(months=1, day=31, days=-6, weekday=FR(0)) 
                           for x in withmooc['hiredate']]
    
    withmooc.head(7)

     


    Results
      empno ename job mgr hiredate sal comm deptno payDATE
    0 7369 SMITH CLERK 7902.0 1980/12/17 800 NaN 20 1981-01-30
    1 7499 ALLEN SALESMAN 7698.0 1981/02/20 1600 300.0 30 1981-03-27
    2 7521 WARD SALESMAN 7698.0 1981/02/22 1250 500.0 30 1981-03-27
    3 7566 JONES MANAGER 7839.0 1981/04/02 2975 NaN 20 1981-04-24
    4 7654 MARTIN SALESMAN 7698.0 1981/09/28 1250 1400.0 30 1981-10-30
    5 7698 BLAKE MANAGER 7839.0 1981/03/01 2850 NaN 30 1981-03-27
    6 7782 CLARK MANAGER 7839.0 1981/01/09 2450 NaN 10 1981-01-30

     


    [정답] relativedelta과 함수 사용 방식

    lambda() 함수 내에 if ~ else 조건문을 사용하여서 근무일자(‘hiredate’)의 일자(day) 부분을 기준으로 급여일을 계산하는 함수를 생성한 후, 입사일자에 set_color() 함수를 적용하여서 입사일 기준 최초 급여 수령 일자를 출력한다.

     

    Python Programming
    withmooc = copy.copy(emp)
    withmooc
    
    def set_color(row):
        if pd.to_datetime(row).day <= 15 :
            chg_day = pd.to_datetime(row, format='%Y %m %d') + relativedelta(day=31, days=-6, weekday=FR(0))
        else:
            chg_day = pd.to_datetime(row, format='%Y %m %d') + relativedelta(months=1, day=31, days=-6, weekday=FR(0))
    
        return chg_day
    
    # withmooc = withmooc.assign(payDATE=withmooc['hiredate'].apply(set_color))  # assign
    
    withmooc['payDATE'] = withmooc['hiredate'].apply(lambda x : set_color(x))
    
    withmooc.head(7)

     


    Results
      empno ename job mgr hiredate sal comm deptno payDATE
    0 7369 SMITH CLERK 7902.0 1980/12/17 800 NaN 20 1981-01-30
    1 7499 ALLEN SALESMAN 7698.0 1981/02/20 1600 300.0 30 1981-03-27
    2 7521 WARD SALESMAN 7698.0 1981/02/22 1250 500.0 30 1981-03-27
    3 7566 JONES MANAGER 7839.0 1981/04/02 2975 NaN 20 1981-04-24
    4 7654 MARTIN SALESMAN 7698.0 1981/09/28 1250 1400.0 30 1981-10-30
    5 7698 BLAKE MANAGER 7839.0 1981/03/01 2850 NaN 30 1981-03-27
    6 7782 CLARK MANAGER 7839.0 1981/01/09 2450 NaN 10 1981-01-30

     


    3. R Programming (R Package)

    • if~else 구문은 날짜형을 수치형으로 반환

    [참고] 행렬 또는 데이터프레임의 모든 행에 일괄적으로 함수 적용하기


    [링크] Apply a function to every row of a matrix or a data frame

    R Programming
    %%R
    a = data.frame(t(iris[1:10,1:3]))
    b = iris[1:10,1:3]
    print(a)
    print(b)
    
    print( apply(b, 1 , prod) )                             # 관측치 행별 변수의 곱
    print( vapply(a, prod, 0) )                             # 열기준 관측치의 곱
    print( sapply(a, prod) )                                # 열기준 관측치의 곱
    print( apply(iris[1:10,1:3], 1 , prod) )                # 관측치 행별 변수의 곱
    print( vapply(data.frame(t(iris[1:10,1:3])), prod, 0) ) # 열기준 관측치의 곱
    print( sapply(data.frame(t(iris[1:10,1:3])), prod) )    # 열기준 관측치의 곱

     

    Results
                  X1  X2  X3  X4  X5  X6  X7  X8  X9 X10
    Sepal.Length 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9
    Sepal.Width  3.5 3.0 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1
    Petal.Length 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5
       Sepal.Length Sepal.Width Petal.Length
    1           5.1         3.5          1.4
    2           4.9         3.0          1.4
    3           4.7         3.2          1.3
    4           4.6         3.1          1.5
    5           5.0         3.6          1.4
    6           5.4         3.9          1.7
    7           4.6         3.4          1.4
    8           5.0         3.4          1.5
    9           4.4         2.9          1.4
    10          4.9         3.1          1.5
         1      2      3      4      5      6      7      8      9     10 
    24.990 20.580 19.552 21.390 25.200 35.802 21.896 25.500 17.864 22.785 
        X1     X2     X3     X4     X5     X6     X7     X8     X9    X10 
    24.990 20.580 19.552 21.390 25.200 35.802 21.896 25.500 17.864 22.785 
        X1     X2     X3     X4     X5     X6     X7     X8     X9    X10 
    24.990 20.580 19.552 21.390 25.200 35.802 21.896 25.500 17.864 22.785 
         1      2      3      4      5      6      7      8      9     10 
    24.990 20.580 19.552 21.390 25.200 35.802 21.896 25.500 17.864 22.785 
        X1     X2     X3     X4     X5     X6     X7     X8     X9    X10 
    24.990 20.580 19.552 21.390 25.200 35.802 21.896 25.500 17.864 22.785 
        X1     X2     X3     X4     X5     X6     X7     X8     X9    X10 
    24.990 20.580 19.552 21.390 25.200 35.802 21.896 25.500 17.864 22.785 

     


    if ~ else 조건문을 사용하여서 근무일자(‘hiredate’)의 일자(day) 부분을 기준으로 급여일을 계산하는 사용자 정의 함수(SalPay.function)를 생성한 후, 입사일자에 SalPay.function 함수를 적용하여서 입사일 기준 최초 급여 수령 일자를 출력한다.

    • rollback 함수 : 기준일자 이전 월의 마지막 날짜를 반환한다.
    • lubridate::ceiling_date : 기준일자를 사용자가 지정한 올림 기준 인수에 따라 올림하여서 해당 날짜를 반환한다.
    • 첫 번째 조건문 : 당월 마지막 일자에서 1주일 이전 날짜를 검색하고, 이 날짜를 기준으로 이후 가장 가까운 금요일로 날짜를 올림하여 해당일자를 반환한다. (week_start : 7 = Sunday, 1 = Monday, 5 = Friday)
    • 두 번째 조건문 : 다음달 마지막 일자에서 1주일 이전 날짜를 검색하고, 이 날짜를 기준으로 이후 가장 가까운 금요일로 날짜를 올림하여 해당일자를 반환한다. (week_start : 7 = Sunday, 1 = Monday, 5 = Friday)
    • ifelse은 날짜형(date)을 수치형(num)으로 반환하기 때문에 계산된 급여 수령 일자(‘payDATE’)의 데이터 자료형을 입사일자(‘hiredate’)의 데이터 자료형인 날짜(‘date’)로 변환한다.

     

    R Programming
    %%R
    
    library(lubridate)
    withmooc <- emp
    
    SalPay.function <- function(x) {
        if (lubridate::day(x) <= 15)
        {
            var=(lubridate::ceiling_date(  (lubridate::rollback(x + months(1)) - days(7)) , unit = "weeks" ,week_start=5))
            return (var)
        } else {
            var=(lubridate::ceiling_date(  (lubridate::rollback(x + months(2)) - days(7)) , unit = "weeks" ,week_start=5))
            return (var)
        }
    }
    
    # withmooc$payDATE <- vapply(withmooc$hiredate, FUN=SalPay.function,0)
    
    withmooc$payDATE <- sapply(withmooc$hiredate, FUN=SalPay.function)
    
    class(withmooc$payDATE) <- class(withmooc$hiredate)  # payDATE에 hiredate의 날짜형을 지정
    
    
    withmooc[1:7, ]

     

    Results
    # A tibble: 7 x 9
      empno ename  job        mgr hiredate     sal  comm deptno payDATE   
      <dbl> <chr>  <chr>    <dbl> <date>     <dbl> <dbl>  <dbl> <date>    
    1  7369 SMITH  CLERK     7902 1980-12-17   800    NA     20 1981-01-30
    2  7499 ALLEN  SALESMAN  7698 1981-02-20  1600   300     30 1981-03-27
    3  7521 WARD   SALESMAN  7698 1981-02-22  1250   500     30 1981-03-27
    4  7566 JONES  MANAGER   7839 1981-04-02  2975    NA     20 1981-04-24
    5  7654 MARTIN SALESMAN  7698 1981-09-28  1250  1400     30 1981-10-30
    6  7698 BLAKE  MANAGER   7839 1981-03-01  2850    NA     30 1981-03-27
    7  7782 CLARK  MANAGER   7839 1981-01-09  2450    NA     10 1981-01-30

     


    ifelse 조건문을 사용하여서 입사일자(‘hiredate’)에서 일자(day) 부분을 추출하여서 15일 이전이면 당월 마지막 금요일의 일자를 산출하고, 15일 이후이면 다음 달 마지막 금요일의 일자를 산출한다.

    • ifelse은 날짜형(date)을 수치형(num)으로 반환하기 때문에 계산된 급여 수령 일자(‘payDATE’)의 데이터 자료형을 입사일자(‘hiredate’)의 데이터 자료형인 날짜(‘date’)로 변환한다.
    R Programming
    %%R
    
    withmooc <- emp
    
    withmooc['payDATE'] = base::ifelse(day(withmooc$hiredate) <= 15 ,(lubridate::ceiling_date(  (rollback(withmooc$hiredate + months(1)) - days(7)) , unit = "weeks" ,week_start=5)),
                                       ifelse(day(withmooc$hiredate) > 15, (lubridate::ceiling_date(  (rollback(withmooc$hiredate + months(2)) - days(7)) , unit = "weeks" ,week_start=5)),
                                       NA))
    
    #str(withmooc) # 데이터 구조 확인
    class(withmooc$payDATE) <- class(withmooc$hiredate)  # 날짜형 지정
    
    withmooc[1:5, ]

     

    Results
    # A tibble: 5 x 9
      empno ename  job        mgr hiredate     sal  comm deptno payDATE   
      <dbl> <chr>  <chr>    <dbl> <date>     <dbl> <dbl>  <dbl> <date>    
    1  7369 SMITH  CLERK     7902 1980-12-17   800    NA     20 1981-01-30
    2  7499 ALLEN  SALESMAN  7698 1981-02-20  1600   300     30 1981-03-27
    3  7521 WARD   SALESMAN  7698 1981-02-22  1250   500     30 1981-03-27
    4  7566 JONES  MANAGER   7839 1981-04-02  2975    NA     20 1981-04-24
    5  7654 MARTIN SALESMAN  7698 1981-09-28  1250  1400     30 1981-10-30

     


    dplyr::if_else 조건문을 사용하여서 입사일자(‘hiredate’)에서 일자(day) 부분을 추출하여서 15일 이전이면 당월 마지막 금요일의 일자를 산출하고, 15일 이후이면 다음 달 마지막 금요일의 일자를 산출한다.

    R Programming
    %%R
    
    withmooc <- emp
    
    withmooc['payDATE'] = dplyr::if_else(day(withmooc$hiredate) <= 15 ,(ceiling_date(  (rollback(withmooc$hiredate + months(1)) - days(7)) , unit = "weeks" ,week_start=5)),
                                   dplyr::if_else(day(withmooc$hiredate) > 15, (ceiling_date(  (rollback(withmooc$hiredate + months(2)) - days(7)) , unit = "weeks" ,week_start=5)),
                                                  ymd(NA)))
    
    withmooc[1:5, ]

     

    Results
    # A tibble: 5 x 9
      empno ename  job        mgr hiredate     sal  comm deptno payDATE   
      <dbl> <chr>  <chr>    <dbl> <date>     <dbl> <dbl>  <dbl> <date>    
    1  7369 SMITH  CLERK     7902 1980-12-17   800    NA     20 1981-01-30
    2  7499 ALLEN  SALESMAN  7698 1981-02-20  1600   300     30 1981-03-27
    3  7521 WARD   SALESMAN  7698 1981-02-22  1250   500     30 1981-03-27
    4  7566 JONES  MANAGER   7839 1981-04-02  2975    NA     20 1981-04-24
    5  7654 MARTIN SALESMAN  7698 1981-09-28  1250  1400     30 1981-10-30

     


    data.table::fifelse 조건문을 사용하여서 입사일자(‘hiredate’)에서 일자(day) 부분을 추출하여서 15일 이전이면 당월 마지막 금요일의 일자를 산출하고, 15일 이후이면 다음 달 마지막 금요일의 일자를 산출한다.

    R Programming
    %%R
    
    withmooc <- emp
    
    withmooc['payDATE'] = data.table::fifelse(day(withmooc$hiredate) <= 15 ,(ceiling_date(  (rollback(withmooc$hiredate + months(1)) - days(7)) , unit = "weeks" ,week_start=5)),
                                   data.table::fifelse(day(withmooc$hiredate) > 15, (ceiling_date(  (rollback(withmooc$hiredate + months(2)) - days(7)) , unit = "weeks" ,week_start=5)),
                                                  ymd(NA)))
    
    withmooc[1:5, ]

     

    Results
    # A tibble: 5 x 9
      empno ename  job        mgr hiredate     sal  comm deptno payDATE   
      <dbl> <chr>  <chr>    <dbl> <date>     <dbl> <dbl>  <dbl> <date>    
    1  7369 SMITH  CLERK     7902 1980-12-17   800    NA     20 1981-01-30
    2  7499 ALLEN  SALESMAN  7698 1981-02-20  1600   300     30 1981-03-27
    3  7521 WARD   SALESMAN  7698 1981-02-22  1250   500     30 1981-03-27
    4  7566 JONES  MANAGER   7839 1981-04-02  2975    NA     20 1981-04-24
    5  7654 MARTIN SALESMAN  7698 1981-09-28  1250  1400     30 1981-10-30

     


    4. R Dplyr Package

    dplyr::if_else 조건문을 사용하여서 입사일자(‘hiredate’)에서 일자(day) 부분을 추출하여서 15일 이전이면 당월 마지막 금요일의 일자를 산출하고, 15일 이후이면 다음 달 마지막 금요일의 일자를 산출한다.

    R Programming
    %%R
    
    withmooc <- emp
    
    withmooc %>% 
      mutate(payDATE = dplyr::if_else(day(hiredate) <= 15 ,(ceiling_date(  (rollback(hiredate + months(1)) - days(7)) , unit = "weeks" ,week_start=5)),
                                      dplyr::if_else(day(hiredate) > 15, (ceiling_date(  (rollback(hiredate + months(2)) - days(7)) , unit = "weeks" ,week_start=5)),
                                                  ymd(NA)))
      ) %>% head()

     

    Results
    # A tibble: 6 x 9
      empno ename  job        mgr hiredate     sal  comm deptno payDATE   
      <dbl> <chr>  <chr>    <dbl> <date>     <dbl> <dbl>  <dbl> <date>    
    1  7369 SMITH  CLERK     7902 1980-12-17   800    NA     20 1981-01-30
    2  7499 ALLEN  SALESMAN  7698 1981-02-20  1600   300     30 1981-03-27
    3  7521 WARD   SALESMAN  7698 1981-02-22  1250   500     30 1981-03-27
    4  7566 JONES  MANAGER   7839 1981-04-02  2975    NA     20 1981-04-24
    5  7654 MARTIN SALESMAN  7698 1981-09-28  1250  1400     30 1981-10-30
    6  7698 BLAKE  MANAGER   7839 1981-03-01  2850    NA     30 1981-03-27

     


    5. R sqldf Package

    입사일자에서 일자 부분을 추출하여서 15일 이전이면 당월 마지막 금요일의 일자를 산출하고, 15일 이후이면 다음 달 마지막 금요일의 일자를 산출한다.

    • ‘weekday 5’ : 다음 금요일 (day of week 0-6 with Sunday==0)
    R Programming
    %%R
    
    sqldf("SELECT hiredate,
                  strftime('%d', datetime(hiredate * 3600 * 24,'unixepoch')) this_day, 
                  strftime('%w', datetime(hiredate * 3600 * 24,'unixepoch')) week_day,             
                  date(datetime(hiredate * 3600 * 24,'unixepoch'), 'localtime','+1 months','start of month', '-1 days') last_day,
                  case when strftime('%d', datetime(hiredate * 3600 * 24,'unixepoch')) <= '15'
                       then date(datetime(hiredate * 3600 * 24,'unixepoch'), 'localtime','+1 months','start of month', '-7 days', 'weekday 5') 
                  else date(datetime(hiredate * 3600 * 24,'unixepoch'), 'localtime','+2 months','start of month', '-7 days', 'weekday 5') end payDATE
           FROM emp
        order by substr(HIREDATE,7,2);") %>% head()

     

    Results
         hiredate this_day week_day   last_day    payDATE
    1  1980-12-17       17        3 1980-12-31 1981-01-30
    2  1981-02-20       20        5 1981-02-28 1981-03-27
    3  1981-02-22       22        0 1981-02-28 1981-03-27
    4  1981-04-02       02        4 1981-04-30 1981-04-24
    5  1981-09-28       28        1 1981-09-30 1981-10-30
    6  1981-03-01       01        0 1981-03-31 1981-03-27
    7  1981-01-09       09        5 1981-01-31 1981-01-30
    8  1982-12-09       09        4 1982-12-31 1982-12-31
    9  1981-11-17       17        2 1981-11-30 1981-12-25
    10 1981-09-08       08        2 1981-09-30 1981-09-25
    11 1983-01-12       12        3 1983-01-31 1983-01-28
    12 1981-12-03       03        4 1981-12-31 1981-12-25
    13 1981-12-03       03        4 1981-12-31 1981-12-25
    14 1982-01-23       23        6 1982-01-31 1982-02-26

     


    6. Python pandasql Package

     

    Python Programming
    ps.sqldf(" SELECT  hiredate,    \
                       case when strftime('%d', date(substr(hiredate,1,4)||'-'||substr(hiredate,6,2)||'-'||substr(hiredate,9,2))) <= '15'     \
                            then date(date(substr(hiredate,1,4)||'-'||substr(hiredate,6,2)||'-'||substr(hiredate,9,2)), 'localtime','+1 months','start of month', '-7 days', 'weekday 5')       \
                       else date(date(substr(hiredate,1,4)||'-'||substr(hiredate,6,2)||'-'||substr(hiredate,9,2)), 'localtime','+2 months','start of month', '-7 days', 'weekday 5') end payDATE    \
           FROM emp    \
        order by substr(HIREDATE,7,2); ").head()

     


    Results
      hiredate payDATE
    0 1981/01/09 1981-01-30
    1 1981/11/17 1981-12-25
    2 1983/01/12 1983-01-28
    3 1982/01/23 1982-02-26
    4 1980/12/17 1981-01-30

     


    7. R data.table Package

    data.table::fifelse 조건문을 사용하여서 입사일자(‘hiredate’)에서 일자(day) 부분을 추출하여서 15일 이전이면 당월 마지막 금요일의 일자를 산출하고, 15일 이후이면 다음 달 마지막 금요일의 일자를 산출한다.

    R Programming
    %%R
    
    DT          <- data.table(emp)
    dept_DT     <- data.table(dept)
    salgrade_DT <- data.table(salgrade)
    
    DT[, payDATE := dplyr::if_else(day(hiredate) <= 15 ,(ceiling_date(  (rollback(hiredate + months(1)) - days(7)) , unit = "weeks" ,week_start=5)),
                                      dplyr::if_else(day(hiredate) > 15, (ceiling_date(  (rollback(hiredate + months(2)) - days(7)) , unit = "weeks" ,week_start=5)),
                                                  ymd(NA))),][1:5, ]

     

    Results
       empno  ename      job  mgr   hiredate  sal comm deptno    payDATE
    1:  7369  SMITH    CLERK 7902 1980-12-17  800   NA     20 1981-01-30
    2:  7499  ALLEN SALESMAN 7698 1981-02-20 1600  300     30 1981-03-27
    3:  7521   WARD SALESMAN 7698 1981-02-22 1250  500     30 1981-03-27
    4:  7566  JONES  MANAGER 7839 1981-04-02 2975   NA     20 1981-04-24
    5:  7654 MARTIN SALESMAN 7698 1981-09-28 1250 1400     30 1981-10-30

     


    8. SAS Proc SQL

     

    SAS Programming
    %%SAS sas
    
    
    data back;
         format week_sun week_mon week_tue week_wed week_thu week_fri week_sat yymmddn8.;
         week_sun = intnx( 'week.1', mdy(4,11,2021) , 1);
         week_mon = intnx( 'week.2', mdy(4,11,2021) , 1);
         week_tue = intnx( 'week.3', mdy(4,11,2021) , 1);
         week_wed = intnx( 'week.4', mdy(4,11,2021) , 1);
         week_thu = intnx( 'week.5', mdy(4,11,2021) , 1);     
         week_fri = intnx( 'week.6', mdy(4,11,2021) , 1);
         week_sat = intnx( 'week.7', mdy(4,11,2021) , 1);
    run;
    
    PROC SQL;
      CREATE TABLE STATSAS_1 AS
        Select empno,
               hiredate,
               day(hiredate)                       as hiredate_day,
               intnx('week',hiredate,1)            as week_day format=yymmddn8.,
               intnx ('month', hiredate, 0, 'e' )  as last_day format=yymmddn8.,
    
               case when day(hiredate) <= 15
                    then intnx( 'week.6', intnx ( 'month', hiredate,  0, 'e' ) , 0) 
               else      intnx( 'week.6', intnx ( 'month', hiredate, +1, 'e' ) , 0)  end as payDATE format=yymmddn8.
        from   emp e;
    QUIT;
    PROC PRINT data=STATSAS_1(obs=5);RUN;

     


    Results
    OBS empno hiredate hiredate_day week_day last_day payDATE
    1 7369 1980-12-17 17 19801221 19801231 19810130
    2 7499 1981-02-20 20 19810222 19810228 19810327
    3 7521 1981-02-22 22 19810301 19810228 19810327
    4 7566 1981-04-02 2 19810405 19810430 19810424
    5 7654 1981-09-28 28 19811004 19810930 19811030

     


    9. SAS Data Step

     

    SAS Programming
    %%SAS sas
    
    DATA STATSAS_2;
     set emp;
         hiredate_day = day(hiredate);
         format week_day last_day payDATE yymmddn8.;
         week_day     = intnx('week',hiredate,1);
         last_day     = intnx ('month', hiredate, 0, 'e' );
    
         if day(hiredate) <= 15 then payDATE = intnx( 'week.6', intnx ( 'month', hiredate,  0, 'e' ) , 0);
         else                        payDATE = intnx( 'week.6', intnx ( 'month', hiredate, +1, 'e' ) , 0);
         keep empno hiredate: week_day last_day payDATE;
    RUN;
    PROC PRINT data=STATSAS_2(obs=5);RUN;

     


    Results
    OBS empno hiredate hiredate_day week_day last_day payDATE
    1 7369 1980-12-17 17 19801221 19801231 19810130
    2 7499 1981-02-20 20 19810222 19810228 19810327
    3 7521 1981-02-22 22 19810301 19810228 19810327
    4 7566 1981-04-02 2 19810405 19810430 19810424
    5 7654 1981-09-28 28 19811004 19810930 19811030

     


    10. Python Dfply Package

     

    Python Programming
    from pandas.tseries.offsets import Day,Week,MonthEnd
    from dateutil.relativedelta import TH
    from dateutil.relativedelta import FR
    import copy
    
    emp >> \
      select(X.empno,X.hiredate) >> \
      mutate( last_day   = make_symbolic(pd.to_datetime)(X.hiredate, format="%Y/%m") + MonthEnd(1) ,
              before_day = make_symbolic(pd.to_datetime)(X.hiredate, format="%Y/%m") + MonthEnd(1) - 7*Day(),
              week_day_1 = make_symbolic(pd.to_datetime)(X.hiredate, format="%Y/%m") + MonthEnd(1) - 7*Day() + pd.DateOffset(weekday=FR(0)) ,  # 경고메시지(PerformanceWarning)가 출력 됨
              week_day_2 = make_symbolic(pd.to_datetime)(X.hiredate, format="%Y/%m") + MonthEnd(1) - 7*Day() + 1*Week(weekday=4)            ,  # 4: 금요일
    
              Next_day_1 = make_symbolic(pd.to_datetime)(X.hiredate, format="%Y/%m") + pd.DateOffset(months=1)+ MonthEnd(1) - 7*Day() + pd.DateOffset(weekday=FR(0)),  # 경고메시지(PerformanceWarning)가 출력 됨
              Next_day_2 = make_symbolic(pd.to_datetime)(X.hiredate, format="%Y/%m") + pd.DateOffset(months=1)+ MonthEnd(1) - 7*Day() + 1*Week(weekday=4)             # 4: 금요일
            ) >> \
      head()

     

    Results
    C:\Users\BACK\anaconda3\lib\site-packages\pandas\core\arrays\datetimes.py:691: PerformanceWarning: Non-vectorized DateOffset being applied to Series or DatetimeIndex
      warnings.warn(

      empno hiredate last_day before_day week_day_1 week_day_2 Next_day_1 Next_day_2
    0 7369 1980/12/17 1980-12-31 1980-12-24 1980-12-26 1980-12-26 1981-01-30 1981-01-30
    1 7499 1981/02/20 1981-02-28 1981-02-21 1981-02-27 1981-02-27 1981-03-27 1981-03-27
    2 7521 1981/02/22 1981-02-28 1981-02-21 1981-02-27 1981-02-27 1981-03-27 1981-03-27
    3 7566 1981/04/02 1981-04-30 1981-04-23 1981-04-24 1981-04-24 1981-05-29 1981-05-29
    4 7654 1981/09/28 1981-09-30 1981-09-23 1981-09-25 1981-09-25 1981-10-30 1981-10-30

     


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

    반응형

    댓글