# ##############################################################################
# 학습자 데이터 분석 및 학습 종료 시점 제안 스크립트
# ##############################################################################
# --- 1. 필요 패키지 설치 및 라이브러리 로드 ---
if(!require(dplyr)) install.packages("dplyr")
## Loading required package: dplyr
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
if(!require(ggplot2)) install.packages("ggplot2")
## Loading required package: ggplot2
if(!require(cluster)) install.packages("cluster")
## Loading required package: cluster
library(dplyr) # 데이터 전처리를 위한 패키지
library(ggplot2) # 데이터 시각화를 위한 패키지
library(cluster) # 클러스터링 분석을 위한 패키지
# --- 2. 데이터 불러오기 및 전처리 ---
setwd("C:/Users/HAENURI/Downloads")
tryCatch({
raw_data <- read.csv("kt1.csv")
learner_summary <- raw_data %>%
group_by(user_id) %>%
summarise(
avg_correct = mean(correct, na.rm = TRUE),
avg_elapsed = mean(elapsed_time, na.rm = TRUE),
total_problems = n()
) %>%
as.data.frame()
print("사용자별 데이터 요약 완료:")
head(learner_summary)
scaled_data <- scale(learner_summary[, c("avg_correct", "avg_elapsed")])
# --- 3. 최적의 클러스터 개수(k) 결정 (엘보우 방법) ---
wss <- numeric(10)
for (k in 1:10) {
set.seed(123)
kmeans_model <- kmeans(scaled_data, centers = k, nstart = 25)
wss[k] <- kmeans_model$tot.withinss
}
# 엘보우 차트 시각화
elbow_plot <- ggplot(data.frame(k = 1:10, wss = wss), aes(x = k, y = wss)) +
geom_line(color = "blue") +
geom_point(color = "red", size = 3) +
labs(
title = "엘보우 방법을 이용한 최적의 클러스터 개수(k) 찾기",
x = "클러스터 개수 (k)",
y = "총 군집 내 제곱합 (Total Within Sum of Squares)"
) +
theme_minimal() +
scale_x_continuous(breaks = 1:10)
print(elbow_plot)
cat("엘보우 차트를 보고 꺾이는 지점의 k값을 선택하세요. (예: 3 또는 4)\n")
OPTIMAL_K <- 3
# --- 4. K-평균 클러스터링 실행 ---
set.seed(123)
final_clusters <- kmeans(scaled_data, centers = OPTIMAL_K, nstart = 25)
learner_summary$cluster <- as.factor(final_clusters$cluster)
# --- 5. 클러스터 분석 및 시각화 ---
cluster_centers <- as.data.frame(final_clusters$centers)
colnames(cluster_centers) <- c("avg_correct_scaled", "avg_elapsed_scaled")
print("클러스터별 중심점 (표준화된 값):")
print(cluster_centers)
cluster_analysis <- learner_summary %>%
group_by(cluster) %>%
summarise(
count = n(),
mean_correct = mean(avg_correct),
mean_elapsed = mean(avg_elapsed)
)
print("클러스터별 특성 분석 (실제 값):")
print(cluster_analysis)
cluster_plot <- ggplot(learner_summary, aes(x = avg_correct, y = avg_elapsed, color = cluster)) +
geom_point(alpha = 0.7, size = 3) +
labs(
title = "학습자 클러스터링 결과",
x = "평균 정답률",
y = "평균 풀이 시간 (초)",
color = "클러스터"
) +
theme_minimal() +
scale_color_brewer(palette="Set1")
print(cluster_plot)
# --- 6. 클러스터별 학습 종료 시점(Threshold) 설정 및 시뮬레이션 ---
cat("\n--- 각 클러스터의 특성에 기반한 학습 종료 시점 제안 ---\n\n")
for (userID_to_check in learner_summary$user_id) {
student_data <- raw_data %>% filter(user_id == userID_to_check) %>% arrange(question_id)
student_cluster <- learner_summary$cluster[learner_summary$user_id == userID_to_check]
total_problems_solved <- nrow(student_data)
completion_point <- NA # 종료 시점 (문제 번호)
if (student_cluster == 1) { # '숙련된 학습자' 그룹
threshold_correct_rate <- 1.0
check_range <- 5
if (total_problems_solved >= check_range) {
for (i in check_range:total_problems_solved) {
recent_correct_rate <- mean(student_data$correct[(i-check_range+1):i])
if (recent_correct_rate >= threshold_correct_rate) {
completion_point <- i
break
}
}
}
if (!is.na(completion_point)) {
cat(sprintf("[사용자 ID: %s | 클러스터: %s] 축하합니다! %d번째 문제에서 '숙련 학습자' 기준(최근 %d문제 정답률 %.0f%%)을 달성했습니다. 학습을 종료해도 좋습니다.\n",
userID_to_check, student_cluster, completion_point, check_range, threshold_correct_rate*100))
} else {
cat(sprintf("[사용자 ID: %s | 클러스터: %s] 꾸준히 잘하고 있습니다! 아직 학습 종료 기준에 도달하지 않았지만, 계속 집중해서 풀어보세요.\n",
userID_to_check, student_cluster))
}
} else if (student_cluster == 2) { # '신중한 노력형 학습자' 그룹
threshold_correct_rate <- 0.8
check_range <- 5
if (total_problems_solved >= check_range) {
for (i in check_range:total_problems_solved) {
if (i >= (0.7 * total_problems_solved) && !is.na(total_problems_solved)) {
completion_point <- i
cat(sprintf("[사용자 ID: %s | 클러스터: %s] 대단해요! %d번째 문제까지 풀며 전체의 70%% 이상을 학습했습니다. 충분히 학습했으니 휴식을 취하는 건 어떨까요?\n",
userID_to_check, student_cluster, completion_point))
break
}
recent_correct_rate <- mean(student_data$correct[(i-check_range+1):i])
if (recent_correct_rate >= threshold_correct_rate) {
completion_point <- i
cat(sprintf("[사용자 ID: %s | 클러스터: %s] 실력이 늘고 있어요! %d번째 문제에서 '노력형 학습자' 기준(최근 %d문제 정답률 %.0f%%)을 달성했습니다. 잠시 쉬었다가 다시 시작해도 좋습니다.\n",
userID_to_check, student_cluster, completion_point, check_range, threshold_correct_rate*100))
break
}
}
}
if (is.na(completion_point)) {
cat(sprintf("[사용자 ID: %s | 클러스터: %s] 차분하게 잘 풀고 있습니다. 조금만 더 힘내서 목표를 달성해 보세요!\n",
userID_to_check, student_cluster))
}
} else { # 클러스터 3 및 기타
if (!is.na(total_problems_solved)) {
completion_point_50_percent <- ceiling(0.5 * total_problems_solved)
if (total_problems_solved >= completion_point_50_percent) {
cat(sprintf("[사용자 ID: %s | 클러스터: %s] 절반이나 학습했네요! %d번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.\n",
userID_to_check, student_cluster, total_problems_solved))
} else {
cat(sprintf("[사용자 ID: %s | 클러스터: %s] 이제 시작입니다! 꾸준히 문제를 풀어나가 보세요.\n",
userID_to_check, student_cluster))
}
}
}
}
}, error = function(e) {
cat("오류 발생: ", e$message, "\n")
cat("'kt1.csv' 파일이 작업 디렉토리에 있는지, 그리고 'user_id', 'question_id', 'correct', 'elapsed_time' 컬럼이 있는지 확인해주세요.\n")
})
## [1] "사용자별 데이터 요약 완료:"

## 엘보우 차트를 보고 꺾이는 지점의 k값을 선택하세요. (예: 3 또는 4)
## [1] "클러스터별 중심점 (표준화된 값):"
## avg_correct_scaled avg_elapsed_scaled
## 1 1.1534875 0.7419678
## 2 -0.5535330 0.5875765
## 3 -0.4593811 -0.8530914
## [1] "클러스터별 특성 분석 (실제 값):"
## # A tibble: 3 × 4
## cluster count mean_correct mean_elapsed
## <fct> <int> <dbl> <dbl>
## 1 1 15 0.713 26.1
## 2 2 13 0.415 25.9
## 3 3 22 0.432 23.6

##
## --- 각 클러스터의 특성에 기반한 학습 종료 시점 제안 ---
##
## [사용자 ID: 1 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 2 | 클러스터: 2] 대단해요! 7번째 문제까지 풀며 전체의 70% 이상을 학습했습니다. 충분히 학습했으니 휴식을 취하는 건 어떨까요?
## [사용자 ID: 3 | 클러스터: 1] 축하합니다! 7번째 문제에서 '숙련 학습자' 기준(최근 5문제 정답률 100%)을 달성했습니다. 학습을 종료해도 좋습니다.
## [사용자 ID: 4 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 5 | 클러스터: 1] 축하합니다! 7번째 문제에서 '숙련 학습자' 기준(최근 5문제 정답률 100%)을 달성했습니다. 학습을 종료해도 좋습니다.
## [사용자 ID: 6 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 7 | 클러스터: 2] 대단해요! 7번째 문제까지 풀며 전체의 70% 이상을 학습했습니다. 충분히 학습했으니 휴식을 취하는 건 어떨까요?
## [사용자 ID: 8 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 9 | 클러스터: 2] 대단해요! 7번째 문제까지 풀며 전체의 70% 이상을 학습했습니다. 충분히 학습했으니 휴식을 취하는 건 어떨까요?
## [사용자 ID: 10 | 클러스터: 1] 축하합니다! 5번째 문제에서 '숙련 학습자' 기준(최근 5문제 정답률 100%)을 달성했습니다. 학습을 종료해도 좋습니다.
## [사용자 ID: 11 | 클러스터: 1] 축하합니다! 6번째 문제에서 '숙련 학습자' 기준(최근 5문제 정답률 100%)을 달성했습니다. 학습을 종료해도 좋습니다.
## [사용자 ID: 12 | 클러스터: 1] 꾸준히 잘하고 있습니다! 아직 학습 종료 기준에 도달하지 않았지만, 계속 집중해서 풀어보세요.
## [사용자 ID: 13 | 클러스터: 1] 꾸준히 잘하고 있습니다! 아직 학습 종료 기준에 도달하지 않았지만, 계속 집중해서 풀어보세요.
## [사용자 ID: 14 | 클러스터: 2] 대단해요! 7번째 문제까지 풀며 전체의 70% 이상을 학습했습니다. 충분히 학습했으니 휴식을 취하는 건 어떨까요?
## [사용자 ID: 15 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 16 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 17 | 클러스터: 2] 대단해요! 7번째 문제까지 풀며 전체의 70% 이상을 학습했습니다. 충분히 학습했으니 휴식을 취하는 건 어떨까요?
## [사용자 ID: 18 | 클러스터: 2] 대단해요! 7번째 문제까지 풀며 전체의 70% 이상을 학습했습니다. 충분히 학습했으니 휴식을 취하는 건 어떨까요?
## [사용자 ID: 19 | 클러스터: 2] 대단해요! 7번째 문제까지 풀며 전체의 70% 이상을 학습했습니다. 충분히 학습했으니 휴식을 취하는 건 어떨까요?
## [사용자 ID: 20 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 21 | 클러스터: 2] 대단해요! 7번째 문제까지 풀며 전체의 70% 이상을 학습했습니다. 충분히 학습했으니 휴식을 취하는 건 어떨까요?
## [사용자 ID: 22 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 23 | 클러스터: 2] 실력이 늘고 있어요! 6번째 문제에서 '노력형 학습자' 기준(최근 5문제 정답률 80%)을 달성했습니다. 잠시 쉬었다가 다시 시작해도 좋습니다.
## [사용자 ID: 24 | 클러스터: 1] 축하합니다! 5번째 문제에서 '숙련 학습자' 기준(최근 5문제 정답률 100%)을 달성했습니다. 학습을 종료해도 좋습니다.
## [사용자 ID: 25 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 26 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 27 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 28 | 클러스터: 1] 꾸준히 잘하고 있습니다! 아직 학습 종료 기준에 도달하지 않았지만, 계속 집중해서 풀어보세요.
## [사용자 ID: 29 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 30 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 31 | 클러스터: 1] 꾸준히 잘하고 있습니다! 아직 학습 종료 기준에 도달하지 않았지만, 계속 집중해서 풀어보세요.
## [사용자 ID: 32 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 33 | 클러스터: 1] 꾸준히 잘하고 있습니다! 아직 학습 종료 기준에 도달하지 않았지만, 계속 집중해서 풀어보세요.
## [사용자 ID: 34 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 35 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 36 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 37 | 클러스터: 2] 대단해요! 7번째 문제까지 풀며 전체의 70% 이상을 학습했습니다. 충분히 학습했으니 휴식을 취하는 건 어떨까요?
## [사용자 ID: 38 | 클러스터: 1] 꾸준히 잘하고 있습니다! 아직 학습 종료 기준에 도달하지 않았지만, 계속 집중해서 풀어보세요.
## [사용자 ID: 39 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 40 | 클러스터: 1] 꾸준히 잘하고 있습니다! 아직 학습 종료 기준에 도달하지 않았지만, 계속 집중해서 풀어보세요.
## [사용자 ID: 41 | 클러스터: 1] 축하합니다! 9번째 문제에서 '숙련 학습자' 기준(최근 5문제 정답률 100%)을 달성했습니다. 학습을 종료해도 좋습니다.
## [사용자 ID: 42 | 클러스터: 2] 대단해요! 7번째 문제까지 풀며 전체의 70% 이상을 학습했습니다. 충분히 학습했으니 휴식을 취하는 건 어떨까요?
## [사용자 ID: 43 | 클러스터: 1] 꾸준히 잘하고 있습니다! 아직 학습 종료 기준에 도달하지 않았지만, 계속 집중해서 풀어보세요.
## [사용자 ID: 44 | 클러스터: 1] 축하합니다! 8번째 문제에서 '숙련 학습자' 기준(최근 5문제 정답률 100%)을 달성했습니다. 학습을 종료해도 좋습니다.
## [사용자 ID: 45 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 46 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 47 | 클러스터: 2] 대단해요! 7번째 문제까지 풀며 전체의 70% 이상을 학습했습니다. 충분히 학습했으니 휴식을 취하는 건 어떨까요?
## [사용자 ID: 48 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 49 | 클러스터: 3] 절반이나 학습했네요! 10번째 문제를 풀었습니다. 어려운 부분이 있다면 관련 개념을 다시 확인하고 학습을 이어가는 것을 추천합니다.
## [사용자 ID: 50 | 클러스터: 2] 대단해요! 7번째 문제까지 풀며 전체의 70% 이상을 학습했습니다. 충분히 학습했으니 휴식을 취하는 건 어떨까요?