자습서: R을 사용하여 변동 예측 모델 만들기, 평가 및 점수 매기기
이 자습서에서는 Microsoft Fabric에서 Synapse 데이터 과학 워크플로의 엔드투엔드 예시를 제공합니다. 이 시나리오는 은행 고객의 이탈 여부를 예측하는 모델을 빌드합니다. 변동률 또는 감소율에는 은행 고객이 은행과 사업을 종료하는 비율이 포함됩니다.
이 자습서에서는 다음과 같은 단계를 다룹니다.
- 사용자 지정 라이브러리 설치
- 데이터 로드
- 예비 데이터 분석을 통해 데이터 이해 및 처리
- scikit-learn 및 LightGBM을 사용하여 기계 학습 모델 학습
- 최종 기계 학습 모델 평가 및 저장
- Power BI 시각화를 사용하여 모델 성능 표시
필수 조건
Microsoft Fabric 구독을 구매합니다. 또는 무료 Microsoft Fabric 평가판에 등록합니다.
Microsoft Fabric에 로그인합니다.
홈페이지 왼쪽 아래에 있는 환경 전환기를 사용하여 패브릭으로 전환합니다.
- 필요한 경우 Microsoft Fabric에서 레이크하우스 만들기에 설명된 대로 Microsoft Fabric 레이크하우스를 만듭니다.
Notebook에서 따라 하기
다음 옵션 중 하나를 선택하여 Notebook에서 따를 수 있습니다.
- Synapse 데이터 과학 환경에서 기본 제공 Notebook을 열고 실행합니다.
- GitHub에서 Synapse 데이터 과학 환경으로 Notebook을 업로드합니다.
기본 제공 Notebook 열기
샘플 고객 이탈 Notebook은 이 자습서와 함께 제공됩니다.
이 자습서의 샘플 노트북을 열기 위해서는 데이터 과학 자습서를 위한 시스템 준비의 지침을 따르십시오.
코드를 실행하기 전에 노트북에 레이크하우스를 연결해야 합니다.
GitHub에서 Notebook 가져오기
AIsample - R Bank Customer Churn.ipynb Notebook은 이 자습서와 함께 제공됩니다.
이 자습서를 위한 동봉된 Notebook을 열기 위해서는 데이터 과학 자습서에 필요한 시스템 준비의 지침을 따라 Notebook을 작업 영역으로 가져오십시오.
이 페이지에서 코드를 복사하여 붙여 넣으면 새 Notebook을 만들 수 있습니다.
코드 실행을 시작하기 전에 레이크하우스를 Notebook에 연결해야 합니다.
1단계: 사용자 지정 라이브러리 설치
기계 학습 모델 개발 또는 임시 데이터 분석의 경우 Apache Spark 세션에 대한 사용자 지정 라이브러리를 신속하게 설치해야 할 수 있습니다. 라이브러리를 설치하는 두 가지 옵션이 있습니다.
- 예를 들어
install.packages
및devtools::install_version
인라인 설치 리소스를 사용하여 현재 Notebook에만 설치합니다. - 또는 Fabric 환경을 만들거나, 공개 소스에서 라이브러리를 설치하거나, 사용자 지정 라이브러리를 업로드한 다음, 작업 영역 관리자가 해당 환경을 작업 영역의 기본값으로 연결할 수 있습니다. 그러면 환경의 모든 라이브러리를 작업 영역의 모든 Notebook 및 Spark 작업 정의에서 사용할 수 있게 됩니다. 환경에 대한 자세한 내용은 Microsoft Fabric에서 환경 만들기, 구성 및 사용을 참조하세요.
이 자습서에서는 install.packages()
(을)를 사용하여 imbalance
및 randomForest
라이브러리를 설치합니다. 출력을보다 간결하게 만들도록 quiet
및 TRUE
(을)를 설정합니다.
# Install imbalance for SMOTE
install.packages("imbalance", quiet = TRUE)
# Install the random forest algorithm
install.packages("randomForest", quiet=TRUE)
2단계: 데이터 로드
churn.csv 데이터 세트에는 10,000명의 고객의 변동 상태와 다음을 포함하는 14개의 특성이 포함됩니다.
- 신용 점수
- 지리적 위치(독일, 프랑스, 스페인)
- 성별(남성, 여성).
- 나이
- 재임 기간(해당 은행에서 고객이 된 기간 수)
- 계정 잔액
- 예상 급여
- 고객이 은행을 통해 구매한 제품 수
- 신용 카드 상태(고객에게 신용 카드가 있는지 여부)
- 활성 회원 상태(사용자가 활성 은행 고객인지 여부)
데이터 세트에는 행 번호, 고객 ID 및 고객 성 열도 포함됩니다. 이러한 열의 값은 고객이 은행을 떠나기로 한 결정에 영향을 주지 않아야 합니다.
고객 은행 계좌 폐쇄 이벤트는 해당 고객의 변동을 정의합니다. 데이터 세트 Exited
열은 고객의 중단을 나타냅니다. 이러한 특성에 대한 컨텍스트가 거의 없으므로 데이터 세트에 대한 배경 정보가 필요하지 않습니다. 이러한 특성이 Exited
상태에 어떻게 기여하는지 이해하려고 합니다.
고객 10,000명 중 2037명(약 20%)만이 은행을 떠났습니다. 클래스 불균형 비율 때문에 가상 데이터 생성을 생성하는 것이 좋습니다.
이 표에는 churn.csv
데이터의 미리 보기 샘플이 표시됩니다.
CustomerID | 성 | CreditScore | 지리 | 성별 | 나이 | 보유 | Balance | NumOfProducts | HasCrCard | IsActiveMember | EstimatedSalary | 종료 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
15634602 | 하그레이브 | 619 | 프랑스 | 여성 | 42 | 2 | 0.00 | 1 | 1 | 1 | 101348.88 | 1 |
15647311 | 언덕 | 608 | 스페인 | 여성 | 41 | 1 | 83807.86 | 1 | 0 | 1 | 112542.58 | 0 |
데이터 세트를 다운로드하고 레이크하우스에 업로드
Important
실행하기 전에 Notebook에 레이크하우스를 추가합니다. 그렇게 하지 않으면 오류가 발생합니다.
이 코드는 공개적으로 사용 가능한 버전의 데이터 세트를 다운로드한 다음, 해당 데이터를 Fabric 레이크하우스에 저장합니다.
library(fs)
library(httr)
remote_url <- "https://sdkstorerta.blob.core.windows.net/churnblob"
file_list <- c("churn.csv")
download_path <- "/lakehouse/default/Files/churn/raw"
if (!dir_exists("/lakehouse/default")) {
stop("Default lakehouse not found, please add a lakehouse and restart the session.")
}
dir_create(download_path, recurse= TRUE)
for (fname in file_list) {
if (!file_exists(paste0(download_path, "/", fname))) {
r <- GET(paste0(remote_url, "/", fname), timeout(30))
writeBin(content(r, "raw"), paste0(download_path, "/", fname))
}
}
print("Downloaded demo data files into lakehouse.")
이 Notebook을 실행하는 데 필요한 시간 기록을 시작합니다.
# Record the notebook running time
ts <- as.numeric(Sys.time())
레이크하우스에서 원시 날짜 데이터 읽기
이 코드는 레이크하우스의 Files 구역에서 원시 데이터를 읽습니다.
fname <- "churn.csv"
download_path <- "/lakehouse/default/Files/churn/raw"
rdf <- readr::read_csv(paste0(download_path, "/", fname))
3단계: 예비 데이터 분석 수행
원시 데이터 표시
head()
또는 str()
명령을 사용하여 원시 데이터의 예비 탐색을 수행합니다.
head(rdf)
초기 데이터 정리 수행
R DataFrame을 Spark DataFrame으로 변환해야 합니다. Spark DataFrame에 대한 이러한 작업은 원시 데이터 세트를 정리합니다.
- 모든 열에 누락된 데이터가 있는 행을 삭제합니다.
-
RowNumber
및CustomerId
열에 중복 행을 삭제합니다. -
RowNumber
,CustomerId
,Surname
열을 삭제합니다.
# Transform the R DataFrame to a Spark DataFrame
df <- as.DataFrame(rdf)
clean_data <- function(df) {
sdf <- df %>%
# Drop rows that have missing data across all columns
na.omit() %>%
# Drop duplicate rows in columns: 'RowNumber', 'CustomerId'
dropDuplicates(c("RowNumber", "CustomerId")) %>%
# Drop columns: 'RowNumber', 'CustomerId', 'Surname'
SparkR::select("CreditScore", "Geography", "Gender", "Age", "Tenure", "Balance", "NumOfProducts", "HasCrCard", "IsActiveMember", "EstimatedSalary", "Exited")
return(sdf)
}
df_clean <- clean_data(df)
display
명령을 사용하여 Spark DataFrame을 탐색합니다.
display(df_clean)
이 코드는 범주, 숫자 및 대상 특성을 결정합니다.
# Determine the dependent (target) attribute
dependent_variable_name <- "Exited"
print(dependent_variable_name)
# Obtain the distinct values for each column
exprs = lapply(names(df_clean), function(x) alias(countDistinct(df_clean[[x]]), x))
# Use do.call to splice the aggregation expressions to aggregate function
distinct_value_number <- SparkR::collect(do.call(agg, c(x = df_clean, exprs)))
# Determine the categorical attributes
categorical_variables <- names(df_clean)[sapply(names(df_clean), function(col) col %in% c("0") || distinct_value_number[[col]] <= 5 && !(col %in% c(dependent_variable_name)))]
print(categorical_variables)
# Determine the numerical attributes
numeric_variables <- names(df_clean)[sapply(names(df_clean), function(col) coltypes(SparkR::select(df_clean, col)) == "numeric" && distinct_value_number[[col]] > 5)]
print(numeric_variables)
더 쉽게 처리하고 시각화하려면 정리된 Spark DataFrame을 R DataFrame으로 변환합니다.
# Transform the Spark DataFrame to an R DataFrame
rdf_clean <- SparkR::collect(df_clean)
5개 숫자 요약 표시
상자 플롯을 사용하여 숫자 특성에 대한 5개 숫자 요약(최소 점수, 첫 번째 사분위수, 중앙값, 세 번째 사분위수, 최대 점수)을 표시합니다.
# Set the overall layout of the graphics window
par(mfrow = c(2, 1),
mar = c(2, 1, 2, 1)) # Margin size
for(item in numeric_variables[1:2]){
# Create a box plot
boxplot(rdf_clean[, item],
main = item,
col = "darkgreen",
cex.main = 1.5, # Title size
cex.lab = 1.3, # Axis label size
cex.axis = 1.2,
horizontal = TRUE) # Axis size
}
# Set the overall layout of the graphics window
par(mfrow = c(3, 1),
mar = c(2, 1, 2, 1)) # Margin size
for(item in numeric_variables[3:5]){
# Create a box plot
boxplot(rdf_clean[, item],
main = item,
col = "darkgreen",
cex.main = 1.5, # Title size
cex.lab = 1.3, # Axis label size
cex.axis = 1.2,
horizontal = TRUE) # Axis size
}
종료된 고객 및 종료되지 않은 고객의 분포 표시
범주 특성에서 종료된 고객 및 종료되지 않은 고객의 분포를 표시합니다.
attr_list <- c('Geography', 'Gender', 'HasCrCard', 'IsActiveMember', 'NumOfProducts', 'Tenure')
par(mfrow = c(2, 1),
mar = c(2, 1, 2, 1)) # Margin size
for (item in attr_list[1:2]) {
counts <- table(rdf_clean$Exited, rdf_clean[,item])
barplot(counts, main=item, col=c("darkblue","yellow"),
cex.main = 1.5, # Title size
cex.axis = 1.2,
legend = rownames(counts), beside=TRUE)
}
par(mfrow = c(2, 1),
mar = c(2, 2, 2, 1)) # Margin size
for (item in attr_list[3:4]) {
counts <- table(rdf_clean$Exited, rdf_clean[,item])
barplot(counts, main=item, col=c("darkblue","yellow"),
cex.main = 1.5, # Title size
cex.axis = 1.2,
legend = rownames(counts), beside=TRUE)
}
par(mfrow = c(2, 1),
mar = c(2, 1, 2, 1)) # Margin size
for (item in attr_list[5:6]) {
counts <- table(rdf_clean$Exited, rdf_clean[,item])
barplot(counts, main=item, col=c("darkblue","yellow"),
cex.main = 1.5, # Title size
cex.axis = 1.2,
legend = rownames(counts), beside=TRUE)
}
숫자 특성의 분포 표시
히스토그램을 사용하여 숫자 특성의 빈도 분포를 표시합니다.
# Set the overall layout of the graphics window
par(mfrow = c(2, 1),
mar = c(2, 4, 2, 4) + 0.1) # Margin size
# Create a histogram
for (item in numeric_variables[1:2]) {
hist(rdf_clean[, item],
main = item,
col = "darkgreen",
xlab = item,
cex.main = 1.5, # Title size
cex.axis = 1.2,
breaks = 20) # Number of bins
}
# Set the overall layout of the graphics window
par(mfrow = c(3, 1),
mar = c(2, 4, 2, 4) + 0.1) # Margin size
# Create a histogram
for (item in numeric_variables[3:5]) {
hist(rdf_clean[, item],
main = item,
col = "darkgreen",
xlab = item,
cex.main = 1.5, # Title size
cex.axis = 1.2,
breaks = 20) # Number of bins
}
기능 엔지니어링 수행
이 기능 엔지니어링은 현재 특성을 기반으로 새 특성을 생성합니다.
rdf_clean$NewTenure <- rdf_clean$Tenure / rdf_clean$Age
rdf_clean$NewCreditsScore <- as.numeric(cut(rdf_clean$CreditScore, breaks=quantile(rdf_clean$CreditScore, probs=seq(0, 1, by=1/6)), include.lowest=TRUE, labels=c(1, 2, 3, 4, 5, 6)))
rdf_clean$NewAgeScore <- as.numeric(cut(rdf_clean$Age, breaks=quantile(rdf_clean$Age, probs=seq(0, 1, by=1/8)), include.lowest=TRUE, labels=c(1, 2, 3, 4, 5, 6, 7, 8)))
rdf_clean$NewBalanceScore <- as.numeric(cut(rank(rdf_clean$Balance), breaks=quantile(rank(rdf_clean$Balance, ties.method = "first"), probs=seq(0, 1, by=1/5)), include.lowest=TRUE, labels=c(1, 2, 3, 4, 5)))
rdf_clean$NewEstSalaryScore <- as.numeric(cut(rdf_clean$EstimatedSalary, breaks=quantile(rdf_clean$EstimatedSalary, probs=seq(0, 1, by=1/10)), include.lowest=TRUE, labels=c(1:10)))
원 핫 인코딩 수행
원 핫 인코딩을 사용하여 범주 특성을 숫자 특성으로 변환하여 기계 학습 모델에 공급합니다.
rdf_clean <- cbind(rdf_clean, model.matrix(~Geography+Gender-1, data=rdf_clean))
rdf_clean <- subset(rdf_clean, select = - c(Geography, Gender))
Power BI 보고서를 생성하는 델타 테이블 만들기
table_name <- "rdf_clean"
# Create a Spark DataFrame from an R DataFrame
sparkDF <- as.DataFrame(rdf_clean)
write.df(sparkDF, paste0("Tables/", table_name), source = "delta", mode = "overwrite")
cat(paste0("Spark DataFrame saved to delta table: ", table_name))
예비 데이터 분석의 관찰 요약
- 대부분의 고객은 프랑스 출신입니다. 스페인은 프랑스와 독일에 비해 변동률이 가장 낮습니다.
- 대부분의 고객에게는 신용 카드가 있습니다.
- 일부 고객은 모두 60세 이상이며 신용 점수가 400 미만입니다. 그러나 이상값으로 간주할 수 없습니다.
- 은행 상품이 두 개 이상 있는 고객은 거의 없습니다.
- 비활성 고객은 변동률이 높습니다.
- 성별 및 임기 연도는 은행 계좌를 폐쇄하기로 한 고객의 결정에 거의 영향을 미치지 않습니다.
4단계: 모델 학습 수행
데이터를 배치하면 이제 모델을 정의할 수 있습니다. 임의 포리스트 및 LightGBM 모델을 적용합니다. randomForest 및 LightGBM을 사용하여 몇 줄의 코드로 모델을 구현합니다.
레이크하우스에서 델타 테이블을 로드합니다. 레이크하우스를 원본으로 간주하는 다른 델타 테이블을 사용할 수 있습니다.
SEED <- 12345
rdf_clean <- read.df("Tables/rdf_clean", source = "delta")
df_clean <- as.data.frame(rdf_clean)
randomForest 및 LightGBM 가져오기:
library(randomForest)
library(lightgbm)
학습 및 테스트용 데이터 세트 준비.
set.seed(SEED)
y <- factor(df_clean$Exited)
X <- df_clean[, !(colnames(df_clean) %in% c("Exited"))]
split <- base::sample(c(TRUE, FALSE), nrow(df_clean), replace = TRUE, prob = c(0.8, 0.2))
X_train <- X[split,]
X_test <- X[!split,]
y_train <- y[split]
y_test <- y[!split]
train_df <- cbind(X_train, y_train)
학습 데이터 세트에 SMOTE 적용
모델에서 의사 결정 경계를 효과적으로 학습할 수 있는 소수 클래스의 예가 너무 적기 때문에 불균형 분류에 문제가 있습니다. 이를 처리하기 위해 SMOTE(가상 소수 민족 과다 샘플링 기술)는 소수 클래스에 대한 새 샘플을 합성하는 데 가장 널리 사용되는 기술입니다. 1단계에서 설치한 imblearn
라이브러리를 사용하여 SMOTE에 액세스합니다.
학습 데이터 세트에만 SMOTE를 적용합니다. 원래 데이터에 대한 모델 성능의 유효한 근사치를 얻으려면 테스트 데이터 세트를 원래 불균형 분포에 두어야 합니다. 이 실험은 프로덕션의 상황을 나타냅니다.
먼저 데이터 세트의 클래스 분포를 표시하여 소수 클래스인 클래스를 알아봅니다. 소수 클래스와 과반수 클래스의 비율은 imbalance Ratio
라이브러리에서 imbalance
(와)과 같이 정의됩니다.
original_ratio <- imbalance::imbalanceRatio(train_df, classAttr = "y_train")
message(sprintf("Original imbalance ratio is %.2f%% as {Size of minority class}/{Size of majority class}.", original_ratio * 100))
message(sprintf("Positive class(Exited) takes %.2f%% of the dataset.", round(sum(train_df$y_train == 1)/nrow(train_df) * 100, 2)))
message(sprintf("Negative class(Non-Exited) takes %.2f%% of the dataset.", round(sum(train_df$y_train == 0)/nrow(train_df) * 100, 2)))
학습 데이터 세트:
-
Positive class(Exited)
(은)는 데이터 세트의 20.34%를 차지하는 소수 클래스를 나타냅니다. -
Negative class(Non-Exited)
(은)는 데이터 세트의 79.66%를 차지하는 대다수 클래스를 나타냅니다.
다음 셀은 imbalance
라이브러리의 오버샘플 함수를 다시 작성하여 균형 잡힌 데이터 세트를 생성합니다.
binary_oversample <- function(train_df, X_train, y_train, class_Attr = "Class"){
negative_num <- sum(y_train == 0) # Compute the number of the negative class
positive_num <- sum(y_train == 1) # Compute the number of the positive class
difference_num <- abs(negative_num - positive_num) # Compute the difference between the negative and positive classes
originalShape <- imbalance:::datasetStructure(train_df, class_Attr) # Get the original dataset schema
new_samples <- smotefamily::SMOTE(X_train, y_train, dup_size = ceiling(max(negative_num, positive_num)/min(negative_num, positive_num))) # Use SMOTE to oversample
new_samples <- new_samples$syn_data # Get the synthetic data
new_samples <- new_samples[base::sample(1:nrow(new_samples), size = difference_num), ] # Sample and shuffle the synthetic data
new_samples <- new_samples[, -ncol(new_samples)] # Remove the class column
new_samples <- imbalance:::normalizeNewSamples(originalShape, new_samples) # Normalize the synthetic data
new_train_df <- rbind(train_df, new_samples) # Concatenate original and synthetic data by row
new_train_df <- new_train_df[base::sample(nrow(new_train_df)), ] # Shuffle the training dataset
new_train_df
}
SMOTE에 대한 자세한 내용은 패키지 imbalance
및 CRAN 웹 사이트의 불균형 데이터 세트 리소스 사용을 참조하세요.
학습 데이터 세트 오버샘플링
새로 정의된 오버샘플 함수를 사용하여 학습 데이터 세트에서 오버샘플링을 수행합니다.
library(dplyr)
new_train_df <- binary_oversample(train_df, X_train, y_train, class_Attr="y_train")
smote_ratio <- imbalance::imbalanceRatio(new_train_df, classAttr = "y_train")
message(sprintf("Imbalance ratio after using smote is %.2f%%\n", smote_ratio * 100))
모델 학습
임의 포리스트를 사용하여 다음 네 가지 기능을 사용하여 모델을 학습합니다.
set.seed(1)
rfc1_sm <- randomForest(y_train ~ ., data = new_train_df, ntree = 500, mtry = 4, nodesize = 3)
y_pred <- predict(rfc1_sm, X_test, type = "response")
cr_rfc1_sm <- caret::confusionMatrix(y_pred, y_test)
cm_rfc1_sm <- table(y_pred, y_test)
roc_auc_rfc1_sm <- pROC::auc(pROC::roc(as.numeric(y_test), as.numeric(y_pred)))
print(paste0("The auc is ", roc_auc_rfc1_sm))
임의 포리스트를 사용하여 6가지 기능을 사용하여 모델을 학습합니다.
rfc2_sm <- randomForest(y_train ~ ., data = new_train_df, ntree = 500, mtry = 6, nodesize = 3)
y_pred <- predict(rfc2_sm, X_test, type = "response")
cr_rfc2_sm <- caret::confusionMatrix(y_pred, y_test)
cm_rfc2_sm <- table(y_pred, y_test)
roc_auc_rfc2_sm <- pROC::auc(pROC::roc(as.numeric(y_test), as.numeric(y_pred)))
print(paste0("The auc is ", roc_auc_rfc2_sm))
LightGBM을 사용하여 모델을 훈련합니다.
set.seed(42)
X_train <- new_train_df[, !(colnames(new_train_df) %in% c("y_train"))]
y_train <- as.numeric(as.character(new_train_df$y_train))
y_test <- as.numeric(as.character(y_test))
lgbm_sm_model <- lgb.train(list(objective = "binary", learning_rate = 0.1, max_delta_step = 2, nrounds = 100, max_depth = 10, eval_metric = "logloss"), lgb.Dataset(as.matrix(X_train), label = as.vector(y_train)), valids = list(test = lgb.Dataset(as.matrix(X_test), label = as.vector(as.numeric(y_test)))))
y_pred <- as.numeric(predict(lgbm_sm_model, as.matrix(X_test)) > 0.5)
accuracy <- mean(y_pred == as.vector(y_test))
cr_lgbm_sm <- caret::confusionMatrix(as.factor(y_pred), as.factor(as.vector(y_test)))
cm_lgbm_sm <- table(y_pred, as.vector(y_test))
roc_auc_lgbm_sm <- pROC::auc(pROC::roc(as.vector(y_test), y_pred))
print(paste0("The auc is ", roc_auc_lgbm_sm))
5단계: 최종 기계 학습 모델 평가 및 저장
테스트 데이터 세트에서 저장된 모델의 성능 평가.
ypred_rfc1_sm <- predict(rfc1_sm, X_test, type = "response")
ypred_rfc2_sm <- predict(rfc2_sm, X_test, type = "response")
ypred_lgbm1_sm <- as.numeric(predict(lgbm_sm_model, as.matrix(X_test)) > 0.5)
혼동 행렬을 사용하여 true/false 긍정/부정을 표시합니다. 분류 정확도를 평가하기 위해 혼동 행렬을 그리는 스크립트를 개발합니다.
plot_confusion_matrix <- function(cm, classes, normalize=FALSE, title='Confusion matrix', cmap=heat.colors(10)) {
if (normalize) {
cm <- cm / rowSums(cm)
}
op <- par(mar = c(6,6,3,1))
image(1:nrow(cm), 1:ncol(cm), t(cm[nrow(cm):1,]), col = cmap, xaxt = 'n', yaxt = 'n', main = title, xlab = "Prediction", ylab = "Reference")
axis(1, at = 1:nrow(cm), labels = classes, las = 2)
axis(2, at = 1:ncol(cm), labels = rev(classes))
for (i in seq_len(nrow(cm))) {
for (j in seq_len(ncol(cm))) {
text(i, ncol(cm) - j + 1, cm[j,i], cex = 0.8)
}
}
par(op)
}
다음 네 가지 기능을 사용하여 임의 포리스트 분류자의 혼동 행렬을 만듭니다.
cfm <- table(y_test, ypred_rfc1_sm)
plot_confusion_matrix(cfm, classes=c('Non Churn','Churn'), title='Random Forest with features of 4')
tn <- cfm[1,1]
fp <- cfm[1,2]
fn <- cfm[2,1]
tp <- cfm[2,2]
다음 6개의 기능을 사용하여 임의 포리스트 분류자의 혼동 행렬을 만듭니다.
cfm <- table(y_test, ypred_rfc2_sm)
plot_confusion_matrix(cfm, classes=c('Non Churn','Churn'), title='Random Forest with features of 6')
tn <- cfm[1,1]
fp <- cfm[1,2]
fn <- cfm[2,1]
tp <- cfm[2,2]
LightGBM에 대한 혼동 행렬을 만듭니다.
cfm <- table(y_test, ypred_lgbm1_sm)
plot_confusion_matrix(cfm, classes=c('Non Churn','Churn'), title='LightGBM')
tn <- cfm[1,1]
fp <- cfm[1,2]
fn <- cfm[2,1]
tp <- cfm[2,2]
Power BI에 대한 결과 저장
모델 예측 결과를 Power BI 시각화로 이동하려면 델타 프레임을 레이크하우스에 저장합니다.
df_pred <- X_test
df_pred$y_test <- y_test
df_pred$ypred_rfc1_sm <- ypred_rfc1_sm
df_pred$ypred_rfc2_sm <- ypred_rfc2_sm
df_pred$ypred_lgbm1_sm <- ypred_lgbm1_sm
table_name <- "df_pred_results"
sparkDF <- as.DataFrame(df_pred)
write.df(sparkDF, paste0("Tables/", table_name), source = "delta", mode = "overwrite", overwriteSchema = "true")
cat(paste0("Spark DataFrame saved to delta table: ", table_name))
6단계: Power BI에서 시각화에 액세스
Power BI에서 저장된 테이블에 액세스합니다.
- 왼쪽에서 OneLake 데이터 허브를 선택합니다.
- 이 Notebook에 추가한 레이크하우스 선택
- 이 레이크하우스 열기 구역에서 열기를 선택합니다.
- 리본에서 새 시맨틱 모델을 선택합니다.
df_pred_results
(을)를 선택한 다음 계속을 선택하여 예측에 연결된 새 Power BI 시맨틱 모델을 만듭니다. - 데이터 세트 페이지의 맨 위에 있는 도구에서 새 보고서를 선택하여 Power BI 보고서 작성 페이지를 엽니다.
다음 스크린샷은 몇 가지 예제 시각화를 보여 줍니다. 데이터 패널에는 테이블에서 선택할 델타 테이블과 열이 표시됩니다. 적절한 범주(x) 축과 값(y) 축을 선택한 후 필터 및 함수를 선택할 수 있습니다. 예를 들어 테이블 열의 합계 또는 평균을 선택할 수 있습니다.
참고 항목
스크린샷은 Power BI에서 저장된 예측 결과를 분석하는 예제를 보여 줍니다. 고객 이탈의 실제 사용 사례의 경우 플랫폼 사용자는 주제별 전문 지식과 조직 및 비즈니스 분석 팀과 회사가 메트릭으로 표준화한 내용을 기반으로 시각화를 보다 철저하게 파악해야 할 수 있습니다.
Power BI 보고서에 따르면 은행 상품 중 두 개 이상을 사용하는 고객은 변동률이 더 높습니다. 그러나 두 개 이상의 제품을 가진 고객은 거의 없습니다. (왼쪽 아래 패널의 플롯을 참조하세요.) 은행은 더 많은 데이터를 수집할 뿐만 아니라 더 많은 제품과 상관 관계가 있는 다른 기능도 조사해야 합니다.
독일의 은행 고객은 프랑스와 스페인의 고객에 비해 이탈률이 높습니다. (오른쪽 아래 패널의 플롯을 참조하세요.) 보고서 결과에 따라 고객이 떠나도록 유도한 요인에 대한 조사가 도움이 될 수 있습니다.
중년 고객(25세에서 45세 사이)이 더 많습니다. 45에서 60 사이의 고객은 더 많은 것을 종료하는 경향이 있습니다.
마지막으로 신용 점수가 낮은 고객은 다른 금융 기관을 위해 은행을 떠날 가능성이 큽니다. 은행은 신용 점수와 계좌 잔액이 낮은 고객이 은행에 머물도록 장려하는 방법을 모색해야 합니다.
# Determine the entire runtime
cat(paste0("Full run cost ", as.integer(Sys.time() - ts), " seconds.\n"))