논리연산자 AND,OR는 실무에서 많이 쓰이는 방법이다. R을 처음 시작 하는 컴퓨터 프로그래머는 for문을 많이 사용한다. 하지만 R에서 for문은 속도 측면에서 최악이다. 그리고 AND, OR, IF 문도 for문을 돌리지 않고 dplyr에서 간단하게 사용할 수 있다.
기호 | 의미 |
! | 논리연산자 NOT |
& | 논리연산자 AND |
| | 논리연산자 OR |
< | 미만 |
<= | 이하 |
> | 초과 |
>= | 이상 |
== | 논리연산자 일치 |
!= | 논리연산자 불일치 |
|| | 조건문에서 OR |
&& | 조건문에서 AND |
xor(x,y) | 베타논리합 |
isTRUE(x) | identical(TRUE. X)의 축약 |
3-2 논리연산자
논리연산의 핵심읜 사실에 대한 질문이다. 예를 들어 “이 값이 다른 값보다 큰가? 2개 모두 같은 크기인가?라는 질문에 대해 복수 연산을 하기 위해서는 and,dor,nor와 같은 연산자를 결합하여 표현할 수 있습니다. R언어에서 질문은 참(TRUE)이나 거짓(FALSE)으로 연산하지만 아마도
와 같이 답변이 없는 경우(NA)도 있다. R에서 부동호 (<)는 보다 작은
을 의미하고, 부등호(>)는 보다 큰
을 의미하는 느낌표(!)는 부정을 의미합니다.. (위의 표 참고)
3.2.1 TRUE와 T.FALSE와 F
참에는 T를 사용하고 거짓에는 F를 사용할 수 있지 만. T와 F가 변수가 될 수 있음을 알고 있어야 합니다. 아래의 예제를 참고 하십시오.
TRUE==FALSE
## [1] FALSE
T==F
## [1] FALSE
그러나 다음과 같이 T 와 F가 변수명으로 사용되는 경우 반드시 T가 TRUE이고, F가 FALSE를 의미한다고 판단 할 수 없습니다.
T<-0
T==FALSE
## [1] TRUE
예제의 변수T는 F와 다릅니다.
T!=F
## [1] FALSE
확실히 해두기 위해서는 항상 TRUE와 FALSE를 모두 기입하고 변수명으로 T 또는 F를 절대로 사용하지 않습니다.
3.2.2 실수값에 대한 동등 여부 테스트
부동 소수점 연산을 위한 국제 표준이 있지만, 컴퓨터 상에서 이러한 표준은 R의 통제 범위를 벗어 납니다. 대략, 정수 연산을 에서 까지이지만 분수나 실수에 대해서는 반올림 오류로 힌해 정확도를 잃게 됩니다. 아래의 예제를 보면 알수 있습니다.
x<-sqrt(2)
x*x==2
## [1] FALSE
x
## [1] 1.414214
x*x
## [1] 2
사실 두 값(2의 제곱근의 자승, 실제값 2)은 같지 않습니다. 두값의 차이를 뺄셈을 통하여 알아 볼수 있습니다.
x*x-2
## [1] 4.440892e-16
3.2.3 all.equal을 사용한 부동 소수점 숫자의 동등 여부 확인
컴퓨터 연산에서 사용한 부동 소수점 자릿수의 특성은 일부 기대하지 않은 문제를 발생시킴니다. 예를 들어 0.3에서 0.2를 배면 0.1이므로 다음 논리연산은 TRUE가 되어야 하지만 실제로는 그렇지 않습니다.
x<-0.3-0.2
y<-0.1
x == y
## [1] FALSE
identical 함수도 같은 오류가 발생 합니다.
identical(x,y)
## [1] FALSE
따라서 이에 대한 해결 방법은 미미한 차이를 허용하는 all.equal 함수를 사용합니다.
all.equal(x,y)
## [1] TRUE
if문에서는 직접적으로 all.equl 을 사용하지 않습니다. 대신 isTRUE(all.equal(….)) 또는 identical 함수를 사용합니다.
예제 1
아래는 빅데이터처리기사 시험 결과 입니다. 시험 기준은 평균점수 60점 이상이고, 40점 이하는 과락 이라는 기준이 있습니다. 아래 시험에서 합격자와 불합격자를 조건 연산자를 이용하여 결과를 정리 하십시오.
수험생번호 | 분석기획 | 데이터탐색 | 모델링 | 결과해석 |
A0001 | 60 | 45 | 40 | 55 |
A0002 | 35 | 60 | 40 | 48 |
A0003 | 70 | 70 | 70 | 65 |
A0004 | 55 | 55 | 40 | 39 |
A0005 | 60 | 70 | 70 | 70 |
A0006 | 80 | 60 | 40 | 40 |
A0007 | 80 | 50 | 60 | 50 |
A0008 | 60 | 35 | 50 | 45 |
A0009 | 80 | 65 | 70 | 30 |
A0010 | 60 | 60 | 55 | 50 |
1. 평균점수 이하 케이스
수험생번호 <- c("A0001","A0002","A0003","A0004","A0005","A0006","A0007",
"A0008","A0009","A0010")
분석기획 <-c(60,35,70,55,60,80,80,60,80,60)
데이터탐색<-c(45,60,70,55,70,60,50,35,65,60)
모델링<-c(40,40,70,40,70,40,60,50,70,55)
결과해석<-c(55,48,65,39,70,40,50,45,30,50)
df <- data.frame(수험생번호, 분석기획, 데이터탐색, 모델링, 결과해석)
df
## 수험생번호 분석기획 데이터탐색 모델링 결과해석
## 1 A0001 60 45 40 55
## 2 A0002 35 60 40 48
## 3 A0003 70 70 70 65
## 4 A0004 55 55 40 39
## 5 A0005 60 70 70 70
## 6 A0006 80 60 40 40
## 7 A0007 80 50 60 50
## 8 A0008 60 35 50 45
## 9 A0009 80 65 70 30
## 10 A0010 60 60 55 50
고전적으로 체크 하는 방법 입니다. 조금 길지만 예전에 C, Python, Java언어를 사용 한 경험이 있다면 쉽게 이해 할 수 있는 부분 입니다.
# 첫번째 행 수험생 번호를 제외 하고, 나타냄
x <- df[2:4]
x
## 분석기획 데이터탐색 모델링
## 1 60 45 40
## 2 35 60 40
## 3 70 70 70
## 4 55 55 40
## 5 60 70 70
## 6 80 60 40
## 7 80 50 60
## 8 60 35 50
## 9 80 65 70
## 10 60 60 55
# apply 함수 1 열 계산으로 평균을 구함
avg_score <- apply(x, 1, mean)
avg_score
## [1] 48.33333 45.00000 70.00000 50.00000 66.66667 60.00000 63.33333 48.33333
## [9] 71.66667 58.33333
# 소숫점 정리 round 함수
avg_score <-round(avg_score)
avg_score
## [1] 48 45 70 50 67 60 63 48 72 58
# 빈 vector 만들기
check <-c()
# 합격 여부 확인 for 문
for(i in 1:length(avg_score)){
if(avg_score[i] >= 60){
check<-c(check, "YES")
} else {
check<-c(check,"NO")
}
}
# 데이터 합치기
df1 <- data.frame(df, 평균점수 = avg_score , 평균점수충족 = check )
df1
## 수험생번호 분석기획 데이터탐색 모델링 결과해석 평균점수 평균점수충족
## 1 A0001 60 45 40 55 48 NO
## 2 A0002 35 60 40 48 45 NO
## 3 A0003 70 70 70 65 70 YES
## 4 A0004 55 55 40 39 50 NO
## 5 A0005 60 70 70 70 67 YES
## 6 A0006 80 60 40 40 60 YES
## 7 A0007 80 50 60 50 63 YES
## 8 A0008 60 35 50 45 48 NO
## 9 A0009 80 65 70 30 72 YES
## 10 A0010 60 60 55 50 58 NO
apply(객체, 행렬선택, 함수)를 이용하면, 열 계산을 할수 있습니다.. 하지만, 수험생번호는 숫자열이 아니기 때문에, 이부분을 빼고 행을 선택 하였습니다.. x <- df[2:4]
apply함수에서 (x, 1, mean)을 사용하면, 객체 x 의 열, 평균함수로 연산할 수 있습니다. 그리고 round 함수를 이용해서, 반올림 처리 하였습니다. 빈 vector를 만들어, for 문을 돌려, 평균점수와 합격 여부를 조건문 >=
을 이용해서 판정(“YES”,“NO”)하였습니다.
dplyr 패키지를 이용하는 방법
dpylyr을 사용하게 되면, 위에서 사용하였던 방법이 단 4줄로 끝나게 된다. R Base 함수에서 apply
함수로 열을 구할 수 있지만, rowMeans()
를 이용 해서 행의 평균을 계산 할 수 있습니다. 그런 다음에 ifelse()
함수를 사용를 사용하여,
# dplyr 라이브러리 불러오기
library(dplyr)
##
## 다음의 패키지를 부착합니다: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
# dplyr을 이용하는 방법
df2 <- df %>%
mutate(평균점수 = rowMeans(df[2:4]),
평균점수 = round(평균점수,0)) %>%
mutate(평균점수충족 = ifelse(평균점수 >=60, "YES", "NO"))
# data.frame 둘이 같은지 확인
all.equal(df1,df2)
## [1] TRUE
2. 과락 케이스
- 일반적인 방법 for 문을 이용하는 방법이다. 데이터 프레임에서 과락여부 빈 필드를 만든 다음, 과목별로 변수를 만들어, 그 중에서 40점 이하인것(OR 조건)을 찾아서 과락된 과목을 찾습니다.
# 미리 데이터 셋 만들기
df1$과락여부 <- ""
# for을 사용 하는 방법 과락여부 판단 OR 문으로 판단하여야 함
for(i in 1:nrow(df1)){
a <- df1$분석기획[i] # 분석기획
b <- df1$데이터탐색[i] # 데이터 탐색
c <- df1$모델링[i] # 모델링
d <- df1$결과해석[i] # 결과해석
if(a<40 | b<40 | c<40 | d<40) {
df1$과락여부[i] <- "YES"
} else {
df1$과락여부[i] <- "NO"
}
}
df1 %>%
select(수험생번호, 평균점수, 평균점수충족, 과락여부)
## 수험생번호 평균점수 평균점수충족 과락여부
## 1 A0001 48 NO NO
## 2 A0002 45 NO YES
## 3 A0003 70 YES NO
## 4 A0004 50 NO YES
## 5 A0005 67 YES NO
## 6 A0006 60 YES NO
## 7 A0007 63 YES NO
## 8 A0008 48 NO YES
## 9 A0009 72 YES YES
## 10 A0010 58 NO NO
최종합격은 평균점수충족여부(YES)와 과락여부(NO)를 두가지 조건을 충족 하는 AND 조건이 맞아야 합니다. 따라서 아래와 같이 for 문을 돌리면, 최종합격 여부를 산출 할수 있습니다.
# 합격여부 필드 초기화
df1$합격여부 <- ""
# 최종합격 for 문을 활용 평균이상이 YES, 이고
# 과락여부가 NO인 경우 합격임
for(i in 1:nrow(df1)){
a <- df1$평균점수충족[i]
b <- df1$과락여부[i]
if(a == "YES" && b == "NO"){
df1$합격여부[i] <- "합격"
} else {
df1$합격여부[i] <- "불합격"
}
}
df1 %>%
select(수험생번호, 평균점수, 평균점수충족, 과락여부, 합격여부)
## 수험생번호 평균점수 평균점수충족 과락여부 합격여부
## 1 A0001 48 NO NO 불합격
## 2 A0002 45 NO YES 불합격
## 3 A0003 70 YES NO 합격
## 4 A0004 50 NO YES 불합격
## 5 A0005 67 YES NO 합격
## 6 A0006 60 YES NO 합격
## 7 A0007 63 YES NO 합격
## 8 A0008 48 NO YES 불합격
## 9 A0009 72 YES YES 불합격
## 10 A0010 58 NO NO 불합격
dplyr을 활용한 합격여부 확인
dplyr을 이용하면 엑셀에서 사용하는 것처럼 ifelse 함수로 모든 조건문을 제어 할수 있습니다. 즉 R에서는 굳이 for문을 돌리지 않고도, 모든 연산을 할수 있습니다. for 문을 사용하는 것은 Big Data연산에서 속도 느림 현상이 발생 할 수 있습니다.
df2 %>%
mutate(과락여부 = ifelse(분석기획<40 | 데이터탐색<40 |
모델링<40 | 결과해석<40,
"YES", "NO")) %>%
mutate(합격여부 = ifelse(평균점수충족 == "YES" & 과락여부 =="NO",
"YES","NO")) %>%
select(수험생번호, 평균점수, 평균점수충족, 과락여부, 합격여부)
## 수험생번호 평균점수 평균점수충족 과락여부 합격여부
## 1 A0001 48 NO NO NO
## 2 A0002 45 NO YES NO
## 3 A0003 70 YES NO YES
## 4 A0004 50 NO YES NO
## 5 A0005 67 YES NO YES
## 6 A0006 60 YES NO YES
## 7 A0007 63 YES NO YES
## 8 A0008 48 NO YES NO
## 9 A0009 72 YES YES NO
## 10 A0010 58 NO NO NO
지금까지 논리연산자 소개와 예제를 통해서 이를 활용하는 방법을 알아 보았습니다. 위의 사례를 이해하면, 실무 업무를 어느정도 이해를 할 수 있습니다.
댓글 없음:
댓글 쓰기