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

[문자함수와 조건문] 조건에 따라 값을 변경 - 147 (오라클 SQL, R, Python, SAS)

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

포스팅 목차

    147. Given a string of the format ‘nn/nn’ . Verify that the first and last 2 characters are numbers .And that the middle character is ‘/‘ Print the expressions ‘Yes’ IF valid ‘NO’ of not valid . Use the following values to test your solution’12/54’,01/1a,’99/98’?

     

    * ‘nn/nn’ 형태의 문자열에 대하여 처음 2개 문자와 마지막 2개 문자가 숫자인지 확인하고, 가운데 문자가 ‘/‘ 존재하는지 확인한다. 조건이 만족하면 “Yes”를 만족하지 않으면 “NO”를 출력한다. 다음 ‘12/54’,’01/1a’,’99/98’ 문자열에 대하여 위 조건문을 확인하시오.


    • Oracle : DECODE 함수, TRANSLATE(), SUBSTR(), TRUNC(), LENGTH(), ROUND(), CASE WHEN 조건문
    • 파이썬 Pandas : str.contains(), np.select(), translate(), ord(), strip(), .join() 문자열 결합, re.findall()
    • R 프로그래밍 : stringr::str_detect(), base::grepl(), Data.frame(), dplyr::case_when(), str_detect(), lapply(), function(x) 사용자 정의 함수
    • R Dplyr Package : dplyr::case_when(), stringr::str_detect, grepl()
    • R sqldf Package : REPLACE(), grepl(), 사용자 정의 함수, count(), AVG(), gsubfn 패키지(gsubfn::fn$sqldf) 외부 변수 참조, paste(), sprintf(), For Loop 반복문, sqlite_version(), 지역 변수 생성
    • Python pandasql Package : REPLACE()
    • R data.table Package : dplyr::case_when(), stringr::str_detect(), grepl()
    • SAS Proc SQL : NOTDIGIT 함수, SUBSTR, CASE WHEN 조건문, prxmatch 정규식 함수
    • SAS Data Step : NOTDIGIT 함수, SUBSTR, CASE WHEN 조건문, prxmatch 정규식 함수
    • Python Dfply Package : str.contains(), make_symbolic(), np.select, str.contains(), 정규식 포맷
    • 파이썬 Base 프로그래밍 :

     


    1. Oracle(오라클)

    첫 번째 조건절에서 주어진 문자열 ‘11/1a’에서 처음 2개 문자를 추출하여서 ‘#1234567980.’를 ‘.’으로 변경 후 별도의 문자가 존재하지 않으면 ‘YES’를 반환하고 다른 문자가 존재하며 ‘NO’를 반환한다. 두 번째 조건절에서 주어진 문자열 ‘11/1a’에서 마지막 2개 문자를 추출하여서 ‘#1234567980.’를 ‘.’으로 변경 후 별도의 문자가 존재하지 않으면 ‘YES’를 반환하고 다른 문자가 존재하며 ‘NO’를 반환한다. 세 번째 조건절에서는 가운데 문자를 추출하여서 해당 문자가 ‘/‘이면 ‘YES’를 반환하고 다른 문자인 경우 ‘NO’를 반환한다. 3개의 조건절은 비교하여 모두 만족하는 경우 ‘YES’를 반환하고, 불만족하는 경우가 있으면 ‘NO’를 반환한다.

     

    Oracle Programming
    select DECODE(TRANSLATE(SUBSTR('11/1a',0,TRUNC(LENGTH('11/1a')/2)),'#1234567980.',''),NULL,'YES','NO') VAR1,
           DECODE(TRANSLATE(substr('11/1a',round(length('11/1a')/2)+1,TRUNC(LENGTH('11/1a')/2)),'#1234567980.',''),NULL,'YES','NO') VAR2,
           substr('11/1a',round(length('11/1a')/2),1) VAR3,
           (CASE WHEN DECODE(TRANSLATE(SUBSTR('11/1a',0,TRUNC(LENGTH('11/1a')/2)),'#1234567980.',''),NULL,'YES','NO') = 'YES'
                  and DECODE(TRANSLATE(substr('11/1a',round(length('11/1a')/2)+1,TRUNC(LENGTH('11/1a')/2)),'#1234567980.',''),NULL,'YES','NO') = 'YES'
                  AND substr('11/1a',round(length('11/1a')/2),1)='/' 
            THEN 'YES' ELSE 'NO' END) STRING_CHK
    from dual;

     


    2. Python Pandas(파이썬)

    정규식을 사용하여서 VAR 변수가 지정한 정규식을 만족하는 경우 True를 반환하고, 불만족하는 경우 False를 반환한다. 지정한 정규식은 처음 2개의 문자가 2자리 수치형 문자이고, 가운데 문자에 ‘/‘가 위치하고, 마지막 2개 문자 역시 2자리 수치형 문자인 경우에 대하여 검색한다.

     

    Python Programming
    import re
    
    df = pd.DataFrame({'var':['12/54','32/21','1q/22']})
    
    df['var'].str.contains('^[0-9]{2}\/[0-9]{2}$')

     

    Results
    0     True
    1     True
    2    False
    Name: var, dtype: bool

     


    정규식을 사용하여서 VAR 변수가 지정한 정규식을 만족하는 경우 True를 반환하고, 불만족하는 경우 False를 반환한다. 지정한 정규식은 처음 2개의 문자가 2자리 수치형 문자이고, 가운데 문자에 ‘/‘가 위치하고, 마지막 2개 문자 역시 2자리 수치형 문자인 경우에 대하여 검색한다. 문자열 검색 결과에 대하여 np.select 조건절을 사용하여서 주어진 조건을 만족하면 ‘Yes’를 반환하고 불만족하는 경우 ‘No’를 반환한다.

     

    Python Programming
    import re
    
    df = pd.DataFrame({'var':['12/54','32/21','1q/22']})
    
    np.select( [ df['var'].str.contains('^[0-9]{2}\\/[0-9]{2}$') ],
               ['Yes'], default = 'No')

     

    Results
    array(['Yes', 'Yes', 'No'], dtype='<U3')

     


    [참고] Translate 함수

    : 아래 예제는 Translate 함수와 반복문을 사용하여서 주어진 문자열(‘file_name’)에서 문자를 1개씩 조회하여서 숫자를 공백으로 변경한다.

     

    Python Programming
    file_name = "12/53"
    file_name.translate({ord(c):'' for c in "1234567890"})

     

    Results
    '/'

     


    Python Programming
    file_name = "12/53"
    # file_name.translate(str.maketrans({'1':'a','2':'b','3':'c','4':'d','5':'e'}))
    file_name.translate({ord('1'): 'a', ord('2'): 'b', ord('3'): 'c', ord('4'): 'd', ord('5'): 'e'})
    'ab/ec'

     


    [참고] strip 함수

    : 아래 예제는 strip을 사용하여서 주어진 문자열(‘file_name’)에서 인수로 지정한 숫자를 제거한다.

     

    Python Programming
    file_name = "12/53"
    
    file_name.strip('1234567890')

     

    Results
    '/'

     


    [참고] re.findall 함수

    : re.findall() 함수에 정규식을 인수로 지정하여서 주어진 문자열(‘var’)에서 숫자를 검색하여 추출한다.

     

    Python Programming
    import re
    var = '12/53' 
    new_string = ''.join(re.findall(r'\d+', var))
    
    new_string

     

    Results
    '1253'

     


    3. R Programming (R Package)

    stringr::str_detect() 문자 검색 함수에 정규식을 인수로 지정하여서 VAR 변수가 지정한 정규식을 만족하는 경우 True를 반환하고, 불만족하는 경우 False를 반환한다. 지정한 정규식은 처음 2개의 문자가 2자리 수치형 문자이고, 가운데 문자에 ‘/‘가 위치하고, 마지막 2개 문자 역시 2자리 수치형 문자인 경우에 대하여 검색한다.

     

    R Programming
    %%R
    
    library(stringr)
    df = data.frame(var = c('12/54','32/21','1q/22'))
    
    stringr::str_detect(df$var, '^[0-9]{2}\\/[0-9]{2}$')

     

    Results
    [1]  TRUE  TRUE FALSE

     


    base::grepl 함수에 정규식을 인수로 지정하여서 VAR 변수가 지정한 정규식을 만족하는 경우 True를 반환하고, 불만족하는 경우 False를 반환한다. 지정한 정규식은 처음 2개의 문자가 2자리 수치형 문자이고, 가운데 문자에 ‘/‘가 위치하고, 마지막 2개 문자 역시 2자리 수치형 문자인 경우에 대하여 검색한다.

     

    R Programming
    %%R
    
    df = data.frame(var = c('12/54','32/21','1q/22'))
    
    base::grepl('^[0-9]{2}\\/[0-9]{2}$', df$var) 

     

    Results
    [1]  TRUE  TRUE FALSE

     


    stringr::str_detect() 문자 검색 함수에 정규식을 인수로 지정하여서 VAR 변수가 지정한 정규식을 만족하는 경우 True를 반환하고, 불만족하는 경우 False를 반환한다. 지정한 정규식은 처음 2개의 문자가 2자리 수치형 문자이고, 가운데 문자에 ‘/‘가 위치하고, 마지막 2개 문자 역시 2자리 수치형 문자인 경우에 대하여 검색한다. str_detect() 함수의 반환 결과에 대하여 dplyr::case_when 조건절을 사용하여서 주어진 조건을 만족하면 ‘Yes’를 반환하고 불만족하는 경우 ‘No’를 반환한다.

     

    R Programming
    %%R
    
    df = data.frame(var = c('12/54','32/21','1q/22'))
    
    dplyr::case_when(str_detect(df$var, '^[0-9]{2}\\/[0-9]{2}$') == TRUE ~ "Yes", TRUE ~ "NO") 

     

    Results
    [1] "Yes" "Yes" "NO" 

     


    R Programming
    %%R
    
    df = data.frame(var = c('12/54','32/21','1q/22'))
    
    lapply(df$var, function(x) dplyr::case_when(grepl('^[0-9]{2}\\/[0-9]{2}$', x) ~ "Yes", TRUE ~ "NO") )

     

    Results
    [[1]]
    [1] "Yes"
    
    [[2]]
    [1] "Yes"
    
    [[3]]
    [1] "NO"

     


    4. R Dplyr Package

    stringr::str_detect() 문자 검색 함수에 정규식을 인수로 지정하여서 VAR 변수가 지정한 정규식을 만족하는 경우 True를 반환하고, 불만족하는 경우 False를 반환한다. 지정한 정규식은 처음 2개의 문자가 2자리 수치형 문자이고, 가운데 문자에 ‘/‘가 위치하고, 마지막 2개 문자 역시 2자리 수치형 문자인 경우에 대하여 검색한다. str_detect() 함수의 반환 결과에 대하여 dplyr::case_when 조건절을 사용하여서 주어진 조건을 만족하면 ‘Yes’를 반환하고 불만족하는 경우 ‘No’를 반환한다.

     

    R Programming
    %%R
    
    df = data.frame(var = c('12/54','32/21','1q/22'))
    
    df %>% 
      mutate( var_1 = dplyr::case_when( stringr::str_detect(var, '^[0-9]{2}\\/[0-9]{2}$') ~ "Yes", TRUE ~ "NO") ,
              var_2 = dplyr::case_when( grepl('^[0-9]{2}\\/[0-9]{2}$', var) ~ "Yes", TRUE ~ "NO") 
    )

     

    Results
        var var_1 var_2
    1 12/54   Yes   Yes
    2 32/21   Yes   Yes
    3 1q/22    NO    NO

     


    5. R sqldf Package

    [SQLite 가이드] [링크] 

    R Programming
    %%R
    
    df = data.frame(var = c('12/54','32/21','1q/22'))
    
    sqldf("SELECT CASE WHEN REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(var,'1',''),'2',''),'3',''),'4',''),'5',''),'6',''),'7',''),'8',''),'9',''),'0',''),'/','') ='' THEN 'Y'
                  ELSE 'N' END VAR
           from df
         ")

     

    Results
      VAR
    1   Y
    2   Y
    3   N

     


    R에서 정규식을 사용하여 처음 2개 문자와 마지막 2개 문자가 숫자이고 가운데 문자가 ‘/‘ 존재하는지 확인하는 함수를 작성하여서 var 변수에 함수를 적용하여 반환된 결과를 sqldf에서 출력한다.

    R Programming
    %%R
    
    df <- data.frame(var = c('12/54','32/21','1q/22'))
    
    year <- function(data){ df$var1 <<- grepl('^[0-9]{2}\\/[0-9]{2}$', df$var); df}
    
    fn$sqldf(c("SELECT * FROM df;","select * from main.df"), method = function(x) data.frame(year(df$var)), verbose = TRUE)       

     


    R Programming
    %%R
    
    data <- data.frame(name=c("v1","v2","v3"),value=c(5,3,NA))
    
    avgNA <- function(x) { 
                           x <- deparse(substitute(x))
                           sprintf("case when count(%s) = count(*) then avg(%s) else null end", x, x)
                         }
    fn$sqldf("select `avgNA(empno)` as value from emp")

     

    Results
         value
    1 7726.571

     


    R Programming
    %%R
    
    sqldf(" select case when count(empno) = count(*) then avg(empno) else null end as value
            from emp")

     

    Results
         value
    1 7726.571

     


    [참고] fn$sqldf

    R에서 생성한 문자열(‘output’)을 sqldf 내로 호출하여서 검색 조건으로 사용한다.

    • LIKE 연산자를 사용하여서 직무(‘Job’) 문자열 내에 ‘SALE’, ‘CLERK’ , ‘blood’ 문자가 존재하는 경우 해당 직원의 정보를 선택한다.
    R Programming
    %%R
    
    input <- "((SALE) OR (CLERK) OR (blood))"
    print(input)
    print("---------------------------------------------------------------------------")
    output <- gsubfn::gsubfn("\\(([A-Za-z0-9 ]+)\\)", ~ sprintf("(job LIKE '%%%s%%')", x), input) 
    print(output)
    print("---------------------------------------------------------------------------")
    fn$sqldf("select * from emp where $output", verbose = TRUE)

     

    Results
    [1] "((SALE) OR (CLERK) OR (blood))"
    [1] "---------------------------------------------------------------------------"
    [1] "((job LIKE '%SALE%') OR (job LIKE '%CLERK%') OR (job LIKE '%blood%'))"
    [1] "---------------------------------------------------------------------------"
    sqldf: library(RSQLite)
    sqldf: m <- dbDriver("SQLite")
    sqldf: connection <- dbConnect(m, dbname = ":memory:")
    sqldf: initExtension(connection)
    sqldf: dbWriteTable(connection, 'emp', emp, row.names = FALSE)
    sqldf: dbGetQuery(connection, 'select * from emp where ((job LIKE '%SALE%') OR (job LIKE '%CLERK%') OR (job LIKE '%blood%'))')
    sqldf: dbDisconnect(connection)
      empno  ename      job  mgr   hiredate  sal comm deptno
    1  7369  SMITH    CLERK 7902 1980-12-17  800   NA     20
    2  7499  ALLEN SALESMAN 7698 1981-02-20 1600  300     30
    3  7521   WARD SALESMAN 7698 1981-02-22 1250  500     30
    4  7654 MARTIN SALESMAN 7698 1981-09-28 1250 1400     30
    5  7844 TURNER SALESMAN 7698 1981-09-08 1500    0     30
    6  7876  ADAMS    CLERK 7788 1983-01-12 1100   NA     20
    7  7900  JAMES    CLERK 7698 1981-12-03  950   NA     30
    8  7934 MILLER    CLERK 7782 1982-01-23 1300   NA     10

     


    [참고] For loop and sqldf

    R에서 생성한 문자(‘base’)를 sqldf 내로 호출하여서 검색 조건으로 사용한다.

    • DF 데이터에서 년도(‘Year’) 가 1970 인 데이터를 추출한다.
    R Programming
    %%R
    
    DF <- data.frame(a = 1:15, Year_var = rep(1970:1972, each = 5))
    base <- 1970
    print(DF[1:7, ])
    
    print("---------------------------------------------------------------------------")
    
    print( sqldf(paste("select * from DF where Year_var =", year)) )
    
    print( sqldf(sprintf("select * from DF where Year_var = %s", year)) )
    
    fn$sqldf("select * from DF where Year_var = $base")

     

    Results
      a Year_var
    1 1     1970
    2 2     1970
    3 3     1970
    4 4     1970
    5 5     1970
    6 6     1971
    7 7     1971
    [1] "---------------------------------------------------------------------------"
      a Year_var
    1 1     1970
    2 2     1970
    3 3     1970
    4 4     1970
    5 5     1970
      a Year_var
    1 1     1970
    2 2     1970
    3 3     1970
    4 4     1970
    5 5     1970
      a Year_var
    1 1     1970
    2 2     1970
    3 3     1970
    4 4     1970
    5 5     1970

     


    R Programming
    %%R
    
    sqldf("select sqlite_version()")

     

    Results
      sqlite_version()
    1           3.33.0

     


    R에서 지정한 3개의 문자 파라미터를 sqldf 내로 호출하여서 검색 조건으로 사용한다.

    • iris 데이터 에서 Sepal.Length 가 7을 초과하고, 품종(‘species’) 이 “virginica”인 데이터에 대하여 5개의 관측치(‘limit’)를 출력하도록 지정한다.
    • sqldf에서 변수에 마침표(‘.’) 존재 시 오류가 발생하여서 큰 따옴표로("Sepal.Length") 감싸야한다.
    R Programming
    %%R
    
    minSL   <- 7
    limit   <- 5
    species <- "virginica"
    fn$sqldf("select * from iris where \"Sepal.Length\" > $minSL and species = '$species' limit $limit")

     

    Results
      Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
    1          7.1         3.0          5.9         2.1 virginica
    2          7.6         3.0          6.6         2.1 virginica
    3          7.3         2.9          6.3         1.8 virginica
    4          7.2         3.6          6.1         2.5 virginica
    5          7.7         3.8          6.7         2.2 virginica

     


    6. Python pandasql Package

     

    Python Programming
    import copy
    
    df = pd.DataFrame({'var':['12/54','32/21','1q/22']})
    
    ps.sqldf(" SELECT CASE WHEN REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(var,'1',''),'2',''),'3',''),'4',''),'5',''),'6',''),'7',''),'8',''),'9',''),'0',''),'/','') ='' THEN 'Y'   \
                  ELSE 'N' END VAR \
               from df")

     


    Results
      VAR
    0 Y
    1 Y
    2 N

     


    7. R data.table Package

    stringr::str_detect() 문자 검색 함수에 정규식을 인수로 지정하여서 VAR 변수가 지정한 정규식을 만족하는 경우 True를 반환하고, 불만족하는 경우 False를 반환한다. 지정한 정규식은 처음 2개의 문자가 2자리 수치형 문자이고, 가운데 문자에 ‘/‘가 위치하고, 마지막 2개 문자 역시 2자리 수치형 문자인 경우에 대하여 검색한다. str_detect() 함수의 반환 결과에 대하여 dplyr::case_when 조건절을 사용하여서 주어진 조건을 만족하면 ‘Yes’를 반환하고 불만족하는 경우 ‘No’를 반환한다.

     

    R Programming
    %%R
    
    
    df = data.frame(var = c('12/54','32/21','1q/22'))
    
    DT <- data.table(df)
    
    DT[,':='( var_1 = dplyr::case_when( stringr::str_detect(var, '^[0-9]{2}\\/[0-9]{2}$') ~ "Yes", TRUE ~ "NO") ,
              var_2 = dplyr::case_when( grepl('^[0-9]{2}\\/[0-9]{2}$', var) ~ "Yes", TRUE ~ "NO") )]

     

    Results
         var var_1 var_2
    1: 12/54   Yes   Yes
    2: 32/21   Yes   Yes
    3: 1q/22    NO    NO

     


    8. SAS Proc SQL

     

    SAS Programming
    %%SAS sas
    
    DATA WITHMOOC;
         INPUT VAR $5.;
    CARDS;
    12/54
    32/21
    1q/22
    ;
    
    PROC SQL;
      CREATE TABLE STATSAS_1 AS
        Select CASE WHEN NOTDIGIT(SUBSTR(VAR,1,2)) = 0 AND SUBSTR(VAR,3,1) = '/' AND NOTDIGIT(SUBSTR(VAR,4,2)) = 0 THEN 'Yes'
               ELSE 'No' END AS VAR_1,
    
               CASE WHEN prxmatch('/^[0-9]{2}\/[0-9]{2}$/',VAR) = 1 THEN 'Yes' else 'No' end as VAR_2
        from   WITHMOOC;
    QUIT;
    PROC PRINT;RUN;

     

    Results
    OBS VAR_1 VAR_2
    1 Yes Yes
    2 Yes Yes
    3 No No

     


    9. SAS Data Step

     

    SAS Programming
    %%SAS sas
    
    DATA STATSAS_2;
     set WITHMOOC;
         if NOTDIGIT(SUBSTR(VAR,1,2)) = 0 AND SUBSTR(VAR,3,1) = '/' AND NOTDIGIT(SUBSTR(VAR,4,2)) = 0 THEN VAR_1= 'Yes';
         ELSE VAR_1 = 'No';
    
         if prxmatch('/^[0-9]{2}\/[0-9]{2}$/',VAR) = 1 THEN VAR_2= 'Yes';
         ELSE VAR_2 = 'No';
    RUN;
    PROC PRINT;RUN;

     


    Results
    OBS VAR VAR_1 VAR_2
    1 12/54 Yes Yes
    2 32/21 Yes Yes
    3 1q/22 No No

     


    10. Python Dfply Package

    • X.var로 변수 지정 불가능
    Python Programming
    import re
    
    df = pd.DataFrame({'var':['12/54','32/21','1q/22']})
    
    df >> mutate( str_find_1 = X['var'].str.contains('^[0-9]{2}\/[0-9]{2}$') ,
                  str_fidn_2 = make_symbolic(np.select)( [ X['var'].str.contains('^[0-9]{2}\\/[0-9]{2}$') ], ['Yes'], default = 'No'))

     

    Results
      var str_fidn_1 str_fidn_2
    0 12/54 True Yes
    1 32/21 True Yes
    2 1q/22 False No

     


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

    반응형

    댓글