# 전처리


```{r}
# 필요한 라이브러리 로드
library(readr)
library(dplyr)
library(tidyr)
library(ggplot2)
library(stringr)
library(lubridate)
library(tidyverse)

# 필요한 데이터 로드, 저장 및 확인

# 파일 경로는 기기에 따라 수정 필요
file_path <- "C:\\Users\\오권영\\Desktop\\2501\\문데분\\simple.csv"

ytb_df <- read.csv(file_path, fileEncoding = "UTF-8")

head(df)
nrow(df)

#전처리

#1)결측치 확인
# 진짜 NA + 빈 문자열 + "NA"라는 문자열까지 감지
sapply(ytb_df, function(x) sum(is.na(x) | x == "" | x == "NA"))
#description :497, video_tags =4669, language=2780
#2)결측지 제거

# video_tags 결측값 → "기타"로 처리
ytb_df$video_tags[is.na(ytb_df$video_tags)] <- "기타"
ytb_df <- na.omit(ytb_df)

nrow(ytb_df)
#정상 처리 확인
colSums(is.na(ytb_df[c("video_tags","video_category_id")]))

#3)날짜 정제->Date타입으로
ytb_df$video_published <- as.Date(ytb_df$video_published_at)
#4)날짜별 정렬

ytb_df <- ytb_df %>%
  arrange(video_published)


# #오채원

```r

(오채원)
```{r}
# 1) 여러 번 등장한 채널
ytb_df %>%
  group_by(channel_name) %>%
  summarise(count = n()) %>%
  arrange(desc(count))

# 태그 리스트로 나누기
ytb_df$tags <- strsplit(ytb_df$video_tags, ",")

# 2) 전체 태그 순위 확인(중복 영상 포함함)
ytb_df %>%
  select(tags) %>%
  unnest(tags) %>%
  filter(!is.na(tags)) %>%
  group_by(tags) %>%
  summarise(count = n(), .groups = "drop") %>%
  arrange(desc(count))

# 3) 중복 영상 제외 태그 순위
ytb_df %>%
  select(video_id, tags) %>%
  unnest(tags) %>%
  filter(!is.na(tags)) %>%
  distinct(video_id, tags) %>% 
  group_by(tags) %>%
  summarise(count = n(), .groups = "drop") %>%
  arrange(desc(count))
# 4) 가장 오래 인급동을 유지한...
ytb_df %>%
  select(video_title, trending_span) %>%
  arrange(desc(trending_span))

# 5) 좋아요 / 조회수 살펴보기

ytb_df %>%
  mutate(lpv = avg_log_likes / avg_log_views) %>%
  group_by(video_id) %>%
  slice_max(lpv, n = 1, with_ties = FALSE) %>%  # lpv가 가장 큰큰
  ungroup() %>%
  select(video_title, channel_name, lpv) %>%
  arrange(desc(lpv))

# 대부분이 아이돌, kpop 관련 => 충성도 높음

# 6) 좋아요 - 댓글수 많은... (논란 여지 있는?)
ytb_df %>%
  mutate(lmc = avg_log_likes - avg_log_comments) %>%
  group_by(video_id) %>%
  slice_min(lmc, n = 1, with_ties = FALSE) %>%  # lmc가 가장 작은 한 행만(차이가 가장 크다는...)
  ungroup() %>%
  select(video_title, channel_name, lmc) %>%
  arrange(lmc)
# 7) 월별 인기 동영상
ytb_df %>%
  mutate(
    month = format(as.Date(video_published), "%Y-%m")  # 월 단위로 변환
  ) %>%
  filter(month >= "2023-11" & month <= "2025-05") %>%
  group_by(month, video_id, video_title) %>%
  summarise(count = n(), .groups = "drop") %>%
  group_by(month) %>%
  slice_max(count, n = 5, with_ties = FALSE) %>%
  select(month, video_title, count) %>%
  arrange(month, desc(count))
# 8) 7번의 시각화
# 1. 전처리: 월별 top 10 태그 계산
top_tags <- ytb_df %>%
  mutate(month = format(as.Date(video_published), "%Y-%m")) %>%
  filter(month >= "2023-11" & month <= "2025-05") %>%
  select(month, tags) %>%
  unnest(tags) %>%
  filter(!is.na(tags)) %>%
  group_by(month, tags) %>%
  summarise(count = n(), .groups = "drop") %>%
  group_by(month) %>%
  slice_max(count, n = 10, with_ties = FALSE)

# 2. 월별로 하나씩 그래프 출력
months <- unique(top_tags$month)

for (m in months) {
  cat("\n\n📊", m, "\n")  # 월 출력
  p <- top_tags %>%
    filter(month == m) %>%
    ggplot(aes(x = reorder(tags, count), y = count)) +
    geom_col(fill = "yellowgreen") +
    coord_flip() +
    labs(title = paste("Top 10 Tags in", m), x = "Tag", y = "Count") +
    theme_minimal()
  
  print(p)  # 그래프 출력
  Sys.sleep(1.5)  # 잠시 멈추기 (옵션) — 그래프가 보이게 하려면 IDE에 따라 필요하다네염
}

library(tidyverse)

# 전처리: 월별 top 10 태그 계산
top_tags <- ytb_df %>%
  mutate(month = format(as.Date(video_published), "%Y-%m")) %>%
  filter(month >= "2023-11" & month <= "2025-05") %>%
  select(month, tags) %>%
  unnest(tags) %>%
  filter(!is.na(tags)) %>%
  group_by(month, tags) %>%
  summarise(count = n(), .groups = "drop") %>%
  group_by(month) %>%
  slice_max(count, n = 10, with_ties = FALSE)

# 월 목록 정렬
months <- sort(unique(top_tags$month))

# 월별 그래프 출력
for (m in months) {
  cat("\n\n📊", m, "\n")
  
  plot_data <- top_tags %>% filter(month == m)
  
  p <- ggplot(plot_data, aes(x = reorder(tags, count), y = count, fill = count)) +
  geom_col() +
  scale_fill_gradient(
    low = "yellow",  # 연한 노랑
    high = "yellowgreen", # 진한 노랑
    guide = "none"
  ) +
  coord_flip() +
  labs(
    title = paste("Top 10 Tags in", m),
    x = "Tag",
    y = "Count"
  ) +
  theme_minimal(base_size = 14)

  
  print(p)
  Sys.sleep(1.5)
}

------------여기까지 EDA----------------- 인사이트 : 좋아요, 댓글 등 단순 시청 뿐만 아니라 반응도도 높은 것은 k-pop 관련! 단순히 조회수가 높은 것은 먹방, 브이로그 등임. 우리가 할 수 있는 것은 무엇?


```r

```{r}
# 태그 별 평균 좋아요
tag_likes_avg <- ytb_df %>%
  select(tags, avg_log_likes) %>%
  unnest(tags) %>%
  filter(!is.na(tags)) %>%
  group_by(tags) %>%
  summarise(
    total_likes = sum(avg_log_likes, na.rm = TRUE),
    tag_count = n(),
    avg_likes = total_likes / tag_count
  ) %>%
  arrange(desc(avg_likes))

tag_likes_avg

tag_likes_avg %>%
  slice_max(total_likes, n = 20) %>%
  ggplot(aes(x = reorder(tags, avg_likes), y = avg_likes, fill = avg_likes)) +
  geom_col() +
  coord_flip() +
  scale_fill_gradient(low = "#FFE082", high = "#FF6F00") +
  labs(
    title = "태그별 좋아요 합계 (상위 20개)",
    x = "태그",
    y = "좋아요 합계"
  ) +
  theme_minimal(base_size = 14)

#정진학

```{r}
# 1) 조회수 vs 좋아요 상관관계 시각화
ggplot(ytb_df, aes(x = avg_log_views, y = avg_log_likes)) +
  geom_point(color = "black", alpha = 0.6) +
  labs(title = "view vs likes", x = "view수", y = "likes") +
  theme_minimal() +
  scale_x_log10() +
  scale_y_log10()
# 2) 조회수 vs 댓글 상관관계 시각화
ggplot(ytb_df, aes(x = avg_log_views, y = avg_log_comments)) +
  geom_point(color = "skyblue", alpha = 0.6) +
  labs(title = "View vs Comments", x = "View", y = "Comments") +
  theme_minimal() +
  scale_x_log10() +
  scale_y_log10()
# 3) 조회수 vs 구독자 상관관계 시각화
ggplot(ytb_df, aes(x = avg_log_views, y = channel_subscriber_count)) +
  geom_point(color = "red", alpha = 0.6) +
  labs(title = "조회수 vs 구독자 수", x = "로그 조회수", y = "구독자 수") +
  theme_minimal() +
  scale_x_log10() +
  scale_y_log10()
# 4) 조회수와 가장 관련 있는 요소는? (피어슨 상관계수)
# 변수 추출
df_corr <- ytb_df %>%
  select(avg_log_views, avg_log_likes, avg_log_comments, channel_subscriber_count) %>%
  na.omit()

#피어슨 상관계수 계산
corr_results <- data.frame(
  variable = c("구독자 수", "좋아요 수", "댓글 수"),
  pearson_r = c(
    cor(df_corr$avg_log_views, df_corr$channel_subscriber_count, method = "pearson"),
    cor(df_corr$avg_log_views, df_corr$avg_log_likes, method = "pearson"),
    cor(df_corr$avg_log_views, df_corr$avg_log_comments, method = "pearson")
  )
)
print(corr_results)

#피어슨 상관계수 막대그래프 시각화

ggplot(corr_results, aes(x = reorder(variable, pearson_r), y = pearson_r, fill = variable)) +
  geom_bar(stat = "identity", width = 0.6) +
  geom_text(aes(label = round(pearson_r, 3)), vjust = -0.5, size = 5) +
  labs(title = "조회수와의 피어슨 상관계수",
       x = "변수", y = "피어슨 상관계수") +
  ylim(0, 1) +
  theme_minimal() +
  theme(legend.position = "none",
        text = element_text(size = 14))
# 적은 구독자 대비 높은 좋아유
#구독자 2만 이하 좋아요 수 내림차순
df_20k <- ytb_df %>%
  filter(channel_subscriber_count <= 20000) %>%
  arrange(desc(avg_log_likes)) %>%
  distinct(video_id, .keep_all = TRUE)

#구독자 5만 이하 좋아요 수 내림차순
df_50k <- ytb_df %>%
  filter(channel_subscriber_count <= 50000) %>%
  arrange(desc(avg_log_likes)) %>%
  distinct(video_id, .keep_all = TRUE)

head(df_20k[, c("video_title", "channel_subscriber_count", "avg_log_likes")])
head(df_50k[, c("video_title", "channel_subscriber_count", "avg_log_likes")])

#이수민

```{r}
# 1) 동영상 길이와 인기 지속 기간의 상관관계
# 'PT34M29S' 형식을 초 단위로 변환하는 함수 정의
duration_to_seconds <- function(duration) {
  # 정규식을 이용해 분(M)과 초(S) 추출
  mins <- str_extract(duration, "(?<=PT)\\d+(?=M)")
  secs <- str_extract(duration, "(?<=M)\\d+(?=S)")
  
  # 결측값 간처리: M이나 S가 없으면 0으로 처리
  mins_num <- as.numeric(ifelse(is.na(mins), 0, mins))
  secs_num <- as.numeric(ifelse(is.na(secs), 0, secs))
  
  # 분 * 60 + 초 계산
  return(mins_num * 60 + secs_num)
}

# video_duration 컬럼을 초 단위로 변환
ytb_df$duration_sec <- sapply(ytb_df$video_duration, duration_to_seconds)

# 분 단위 변환
ytb_df$duration_min <- ytb_df$duration_sec / 60

# 변환 후 확인
head(ytb_df[, c("video_duration", "duration_min")])

# 동영상 길이와 인기 지속 기간 사이 상관관계 산점도
ggplot(ytb_df, aes(x = duration_min, y = trending_span)) +
  geom_point(color = "blue", alpha = 0.6) +
  geom_smooth(method = "lm", se = FALSE, color = "red") + # 선형 회귀선
  labs(title = "동영상 길이와 인기 지속 기간의 상관관계",
       x = "동영상 길이 (분)",
       y = "인기 지속 기간 (일)") +
  theme_minimal()

# 선형 회귀 모델 만들기
model <- lm(trending_span ~ duration_min, data = ytb_df)

# 회귀 모델 요약 출력
summary(model)
# 2) 게시 시간대와 영상의 인기
# 인기 지속 기간이 높은 상위 100개 영상 선택
top_100_videos <- ytb_df %>%
  arrange(desc(trending_span)) %>%  # 인기 지속 기간 기준 내림차순 정렬
  head(100)  # 상위 100개 선택

# 업로드 시점을 시각화
ggplot(top_100_videos, aes(x = as.POSIXct(video_published_at, format = "%Y-%m-%d %H:%M:%S"))) +
  geom_histogram(binwidth = 3600, fill = "steelblue", color = "black") +  # 1시간 단위로 binning
  labs(title = "인기 지속 기간이 높은 100개 영상의 업로드 시점",
       x = "업로드 시점", y = "업로드 빈도 (1시간 단위)") +
  theme_minimal()

top_100_videos <- top_100_videos %>%
  mutate(publish_hour = hour(as.POSIXct(video_published_at, format = "%Y-%m-%d %H:%M:%S")))  # 게시 시간대 추출

ggplot(top_100_videos, aes(x = as.factor(publish_hour))) +
  geom_bar(fill = "lightgreen") +
  labs(title = "상위 100개 영상의 게시 시간대 분포",
       x = "게시 시간대 (시)", y = "영상 수") +
  theme_minimal()
# 3) 인기 영상들의 영상 길이
# 인기 지속 기간이 높은 상위 100개 영상 선택
top_100_videos <- ytb_df %>%
  arrange(desc(trending_span)) %>%  # 인기 지속 기간 기준 내림차순 정렬
  head(100)  # 상위 100개 선택

# 'video_duration'을 초 단위로 변환하는 함수 정의
duration_to_seconds <- function(duration) {
  mins <- str_extract(duration, "(?<=PT)\\d+(?=M)")
  secs <- str_extract(duration, "(?<=M)\\d+(?=S)")
  
  mins_num <- as.numeric(ifelse(is.na(mins), 0, mins))
  secs_num <- as.numeric(ifelse(is.na(secs), 0, secs))
  
  return(mins_num * 60 + secs_num)
}

# video_duration 컬럼을 초 단위로 변환
top_100_videos$duration_sec <- sapply(top_100_videos$video_duration, duration_to_seconds)

# 초 단위로 변환된 동영상 길이를 분 단위로 변환
ytb_df$duration_min <- ytb_df$duration_sec / 60

# 영상 길이를 나타내는 히스토그램 그리기
ggplot(top_100_videos, aes(x = duration_min)) +
  geom_histogram(binwidth = 5, fill = "steelblue", color = "black") +  # 1분 단위로 binning
  labs(title = "인기 지속 기간 상위 100개 영상의 영상 길이",
       x = "영상 길이 (분)",
       y = "영상 수") +
  theme_minimal()

ggplot(top_100_videos, aes(x = "", y = duration_min)) +
  geom_boxplot(fill = "lightgreen") +
  labs(title = "인기 지속 기간 상위 100개 영상의 영상 길이 분포",
       x = "", y = "영상 길이 (분)") +
  theme_minimal()

#이혜림