R-Studio KNN(k-nearest neighbors) 을 이용한 머신러닝

class의 floor, sqrt, knn, dplyr의 select, normalize 커스텀 함수

Featured image

파일 소스

우클릭 -> 다른이름으로 링크저장 이용해 주세요
S20191113.zip


메인 사용 함수

normalize 커스텀 min-max 함수(정규화 함수)
floor 내림함수
knn KNN(K-Nearest Neighbor) 알고리즘은 범주를 모르는 어떠한 데이터에 대하여 분류 되어 있는 가장 유사한 예제의 범주로 지정해주는 알고리즘이다.
scale (정규화 함수)
sd 표준편차 함수

소스 코드

# install.packages("class")
library(class)

likelyhood <- read.csv("likelyhood.csv", stringsAsFactors = F)
str(likelyhood)
dim(likelyhood)
colnames(likelyhood)

# 샘플 분리
train_x <- likelyhood[c(1:13), -8]
train_x

train_y <- likelyhood[c(1:13), 8]
train_y


test_x <- likelyhood[c(14:14), -8]
test_x

test_y <- likelyhood[c(14:14), 8]
test_y

# floor <- 내림
k_size_1 <- floor(sqrt(nrow(likelyhood)))
k_size_1

# 의도적인 값 수정
k_size_1 <- ifelse(k_size_1 %% 2 == 0, k_size_1 + 1, k_size_1)
k_size_1

knnpred1 <- knn(train = train_x, test=test_x, cl=train_y, k=k_size_1, prob = T)
knnpred1
# [1] A # A의 사람의 소개팅 성공 확률은?
# attr(,"prob")
# [1] 1 # 확률 100%
# Levels: A B C

############################################################################################
# 파일 이름 : saleinfo.csv
# 쇼핑몰 고객 정보를 담고 있는 엑셀 파일과
# KNN을 이용하여 고객의 구매 여부를 예측해보세요.
# 
# 컬럼 : 나이,월급,구매여부
# 나이와 월급 정보를 이용하여 구매 여부를 파악하는 예시이다.
# 나이와 월급은 Z 표준화 변환을 수행하여 테스트 하도록 한다.
# 테스트할 데이터 정보는 다음과 같다.
# stringsAsFactors : 팩터형 벡터는 자동으로 변환해줌(로지스틱 한것)
df <- read.csv("saleinfo.csv", stringsAsFactors = F)
str(df)
colnames(df)

# Z 표준화 변환 : scale 로 변환시킴
df$age <- scale(df$나이)
df$income <- scale(df$월급)
colnames(df)
str(df)

# 표준화 변환의 공식
df$age2 <- (df$나이 - mean(df$나이)) / sd(df$나이)
head(df$age)
head(df$age2)
colnames(df)

train_x01 <- df[, c(4, 5)]
train_x01

train_y01 <- df[, c(3)]
train_y01

test_x01 <- data.frame(age=44, income=400)
test_x01

k_size_1 <- floor(sqrt(nrow(df)))
k_size_1 <- ifelse(k_size_1 %% 2 == 0, k_size_1+1, k_size_1)
k_size_1

knnpred1 <- knn(train=train_x01, test=test_x01, cl = train_y01, k=k_size_1, prob = T)
# [1] 구매
# attr(,"prob")
# [1] 0.8 # test_x01 고객은 상품을 구매한다고 봐야 한다.
# Levels: 구매 비구매
knnpred1

######################################################################################
# 파일 이름 : customers.csv
# 쇼핑몰에서 회원의 구매 시간대별 소비 지수를 조사한 데이터 셋이 있다.
# 이 정보를 이용하여 해당 구매 고객에 대한 성별을 판단해 보는 
# KNN 모델을 만들어 보세요.
# 이 모델에 대하여 다음 데이터를 이용하여 성별을 예측해보도록 하세요.
# 남자 또는 여자일 확률도 구해 보세요.
df01 <- read.csv("customers.csv", stringsAsFactors = F)
str(df01)
colnames(df01)

# 표준화 변환의 공식
df01$we <- (df01$주말 - mean(df01$주말)) / sd(df01$주말)
df01$mo <- (df01$아침 - mean(df01$아침)) / sd(df01$아침)
df01$an <- (df01$점심 - mean(df01$점심)) / sd(df01$점심)
df01$ni <- (df01$저녁 - mean(df01$저녁)) / sd(df01$저녁)

head(df01$we)
head(df01$we)
colnames(df01)

train_x02 <- df01[, 6:9]
train_x02

train_y02 <- df01[, 5]
train_y02

k_size_1 <- floor(sqrt(nrow(df01)))
k_size_1 <- ifelse(k_size_1 %% 2 == 0, k_size_1+1, k_size_1)
k_size_1

# 테스트 데이터
test_x02 <- data.frame(we=91, mo=12, an=20, ni=50)

knnpred2 <- knn(train=train_x02, test=test_x02, cl = train_y02, k=k_size_1, prob = T)
# [1] 여 # test_x01는 여성 일 확률이 높다
# attr(,"prob")
# [1] 1 # 100% 확률로
# Levels: 남 여
knnpred2

##################################################################################################
library(ggplot2)
library(class)
library(dplyr)

food <- read.csv("food_list.csv", header = T)
food
colnames(food)

tomato <- data.frame(ingredient = "tomato", sweetness = 6, crunchiness = 4)
tomato

ggplot(data=food, aes(x=sweetness, y=crunchiness))+geom_point(aes(color=class, shape=class), size=5)

# k = 1로 테스트 해보기
train_x02 <- select(food, sweetness, crunchiness)
train_y02 <- unlist(select(food, class))

test_x02 <- select(tomato, sweetness, crunchiness)
tmt = knn(train = train_x02, test=test_x02, cl=train_y02, k=1)
tmt

ingredient <- c("grape", "green bean", "orange", "tomato")
sweetness <- c(8, 3, 7, 6)
crunchiness <- c(5, 7, 3, 4)

unknown <- data.frame(ingredient, sweetness, crunchiness)
unknown

# k = 3으로 unknown을 테스트 해보기
k_size_1 <- floor(sqrt(nrow(food)))
k_size_1 <- ifelse(k_size_1 %% 2 == 0, k_size_1+1, k_size_1)
k_size_1

# train_x는 그대로 사용하면 된다.
test_x02 <- unknown[c("sweetness", "crunchiness")]
knnpred2 <- knn(train=train_x02, test=test_x02, cl = train_y02, k=k_size_1, prob = T)

knnpred2
# [1] Fruits     Vegetables Fruits     Fruits    
# attr(,"prob")
# 왼쪽 부터 차례대로 포도 완두콩 오랜지 토마토 의 종류가 무었인지 확률
# 포도는 과일, 완두콩은 채소일 확률 0.67% 등등...
# [1] 1.0000000 0.6666667 1.0000000 0.6666667
# Levels: Fruits Proteins Vegetables

소스 코드 2

wbcd <- read.csv("wisc_bc_data.csv", stringsAsFactors = F)
str(wbcd)
dim(wbcd) # [1] 569  32

wbcd <- wbcd[-1]
unique(wbcd$diagnosis)
table(wbcd$diagnosis)

wbcd$diagnosis <- factor(wbcd$diagnosis, levels = c("B", "M"), labels=c("Benign", "Malignant"))
table(wbcd$diagnosis)
# Benign Malignant 
# 357       212 
357/(357+212)
# [1] 0.6274165

colnames(wbcd)

# wdbc.names.txt 파일 참고
summary(wbcd[c("radius_mean", "area_mean", "smoothness_mean")])
# radius_mean       area_mean      smoothness_mean  
# Min.   : 6.981   Min.   : 143.5   Min.   :0.05263  
# 1st Qu.:11.700   1st Qu.: 420.3   1st Qu.:0.08637  
# Median :13.370   Median : 551.1   Median :0.09587  
# Mean   :14.127   Mean   : 654.9   Mean   :0.09636  
# 3rd Qu.:15.780   3rd Qu.: 782.7   3rd Qu.:0.10530  
# Max.   :28.110   Max.   :2501.0   Max.   :0.16340  

# normalize 함수 정규화
# min-max 알고리즘
normalize <- function(x) {
  return ( (x - min(x))/(max(x) - min(x)) )
}

# 단순 표준화 함수
normalize(c(1, 2, 3, 4, 5))
normalize(c(10, 20, 30, 40, 50))

colnames(wbcd)
wbcd_n <- as.data.frame(lapply(wbcd[2:31], normalize))
summary(wbcd_n[c("radius_mean", "area_mean", "smoothness_mean")])

# 데이터 분리
# 하단 100개를 테스트 용으로 사용
testing_row <- 100
total_row <- nrow(wbcd_n)
training_row <- total_row - testing_row

wbcd_train <- wbcd_n[1:training_row, ]
wbcd_test <- wbcd_n[(training_row+1):total_row, ]

wbcd_train_labels <- wbcd[1:training_row, 1]
wbcd_test_labels <- wbcd[(training_row+1):total_row, 1]

library(class)
k_size <- floor(sqrt(training_row))
k_size <- ifelse(k_size %% 2 == 0, k_size+1, k_size)
k_size

knn_pred <- knn(train = wbcd_train, test = wbcd_test, cl=wbcd_train_labels, k=k_size)
knn_pred

# crosstable 뽑기
# install.packages("gmodels")
library(gmodels)

crossTable <- CrossTable(x = wbcd_test_labels, y = knn_pred, prop.chisq = F)
crossTable

# for문 돌리기
wbcd_train <- wbcd_n[1:training_row, ]
wbcd_test <- wbcd_n[(training_row+1):total_row, ]
for(idx in c(5, 11, 15, 21, 27)) {
  knn_pred <- knn(train=wbcd_train, test=wbcd_test, cl=wbcd_train_labels, k=k_size)
  CrossTable(x = wbcd_test_labels, y = knn_pred, prop.chisq = F)
  cat("----------------------------------------------------------")
}