포스팅 목차
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’ 문자열에 대하여 위 조건문을 확인하시오.
- 파이썬 & R 패키지 호출 및 예제 데이터 생성 링크
- [데이터 추출] 조건에 따라 값을 변경 - 문자함수와 조건문
|
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
- [링크] Replace parts of a string in R
- [링크] Replace String Pattern in sqldf
- [링크] Parsing by Delimitor sqldf
- sqlite3 : [링크] How do I use regex in a SQLite query?
- var 변수에서 0~9까지 숫자와 “/“ 문자를 공백으로 변환 후 Case when 조건문을 사용하여 별도의 문자가 존재하지 않으면 ‘Y’를 다른 문자가 존재하면 ‘N’을 반환한다.
- sqldf에서 TRANSLATE 함수나 정규식 함수 아직 확인 못함
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에서 출력한다.
- fn$ : 예제 링크
- 참고 : [링크] 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에서 생성한 함수를 fn$sqldf를 사용하여서 sqldf 함수내에서 호출하여 사용한다.
- 생성한 함수는 사원번호(‘empno’)의 건수와 총 건수를 집계 후 두 개의 건수가 같으면 평균을 계산하고, 사원번호에 null 값이 존재하여 2 개의 건수가 틀리면 null을 반환한다.
- sqldf(“select * from csvread(‘iris3.dat’)”, method = function(x)
data.frame(fac2num(x[-5]), x[5])) - https://github.com/ggrothendieck/sqldf
- https://www.slideshare.net/yaju88/sazae-jyanken
- [링크] How to force NA/NULL in aggregate function if data contains NA/NULL
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 예제로 만나는 테이블 데이터 전처리 방법 리스트
'통계프로그램 비교 시리즈 > 프로그래밍비교(Oracle,Python,R,SAS)' 카테고리의 다른 글
[비등가 데이터 결합] 특정 조건을 만족하는 데이터 추출 - 상관 서브쿼리(Any) - 149 (오라클 SQL, R, Python, SAS) (0) | 2023.01.03 |
---|---|
[날짜 함수] 특정 조건에 따라 해당 날짜 반환 - 148 (오라클 SQL, R, Python, SAS) (1) | 2023.01.03 |
[날짜 데이터] 날짜 기간 차이 계산 - 현재 날짜 - 146 (오라클 SQL, R, Python, SAS) (0) | 2023.01.02 |
[Case When 조건문] 조건에 따라 값을 변경 - 145 (오라클 SQL, R, Python, SAS) (0) | 2023.01.02 |
[날짜 포맷] 날짜 출력 포맷 지정 - 144 (오라클 SQL, R, Python, SAS) (1) | 2023.01.01 |
댓글