Code
options(encoding = "UTF-8")
Sys.setlocale("LC_CTYPE", "ko_KR.UTF-8")[1] "ko_KR.UTF-8"
options(encoding = "UTF-8")
Sys.setlocale("LC_CTYPE", "ko_KR.UTF-8")[1] "ko_KR.UTF-8"
본 보고서는 미다팀 데이터와 IPTV 데이터 간의 시청률 동등성을 검증하기 위한 최종 분석 결과를 기술합니다. 채널 번호 매핑 이슈를 해결하기 위해 채널명을 기준으로 1:1 매핑을 수행하였으며, 데이터 전처리, 시각화, 기초 통계 검정, 그리고 최종적으로 개별 채널 수준의 동등성 검정(Individual Equivalence Test)을 수행하여 대체 가능성을 판단합니다.
if (!require("readxl")) install.packages("readxl")Loading required package: readxl
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("TOSTER")) install.packages("TOSTER")Loading required package: TOSTER
if (!require("tolerance")) install.packages("tolerance")Loading required package: tolerance
tolerance package, version 3.0.0, Released 2024-04-18
This package is based upon work supported by the Chan Zuckerberg Initiative: Essential Open Source Software for Science (Grant No. 2020-255193).
if (!require("ggplot2")) install.packages("ggplot2")Loading required package: ggplot2
library(readxl)
library(dplyr)
library(TOSTER)
library(tolerance)
library(ggplot2)채널 번호(ID) 기준 매핑 시 1:N 매핑 문제가 발생하여, 채널명을 고유 식별자(Key)로 활용하여 1:1 매핑을 확정했습니다.
# 1. 데이터 로드
file_path <- "C:/Users/kahyu/Desktop/odata.xlsx"
df <- read_excel(file_path, sheet = "Sheet1")
df_clean <- df %>%
select(Mida = 1, IPTV = 2) %>%
mutate(Mida = as.numeric(Mida), IPTV = as.numeric(IPTV)) %>%
filter(!is.na(Mida) & !is.na(IPTV))
# 2. Pairwise Difference 계산
x <- df_clean$Mida - df_clean$IPTV
cat("\n[Pairwise num] N =", length(x), "\n")
[Pairwise num] N = 254
데이터의 분포와 일치도를 시각적으로 확인합니다.
ggplot(df_clean, aes(x = Mida, y = IPTV)) +
geom_point(alpha = 0.6, color = "blue") +
geom_abline(slope = 1, intercept = 0, color = "red", linetype = "dashed", size = 1) +
labs(title = "MidaTeam vs IPTV Share Scatterplot",
x = "MidaTeam Share (%)",
y = "IPTV Share (%)",
caption = "Red dashed line indicates Y = X (Perfect Match)") +
theme_minimal()Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
# 데이터 프레임에 차이 컬럼 추가
df_clean$Diff <- x
mean_val <- mean(x)
median_val <- median(x)
ggplot(df_clean, aes(x = Diff)) +
geom_histogram(aes(y = ..density..), binwidth = 0.05, fill = "gray80", color = "black") +
geom_density(alpha = 0.2, fill = "blue") +
geom_vline(aes(xintercept = mean_val, linetype = "Mean"), color = "black", size = 1) +
geom_vline(aes(xintercept = median_val, linetype = "Median"), color = "red", size = 1) +
scale_linetype_manual(name = "Statistics",
values = c("Mean" = "solid", "Median" = "dashed"),
labels = c(paste0("Mean: ", round(mean_val, 4)),
paste0("Median: ", round(median_val, 4)))) +
labs(title = "Distribution of Differences (Mida - IPTV)",
x = "Difference", y = "Density") +
theme_minimal()Warning: The dot-dot notation (`..density..`) was deprecated in ggplot2 3.4.0.
ℹ Please use `after_stat(density)` instead.
평균 차이 유의성 및 기본적인 정규성을 검정합니다.
검정 내용: 두 그룹의 평균 차이가 통계적으로 유의미한지 확인.
가설: \(H_0: \mu_{diff} = 0\) vs \(H_1: \mu_{diff} \neq 0\)
검정 결과: P-value > 0.05
결과 해석: 유의수준 0.05보다 P-value가 크므로 귀무가설을 기각하지 못했습니다. 즉, 미다팀과 IPTV 시청률 간의 평균적인 차이는 통계적으로 유의미하지 않으며, 두 그룹의 평균은 유사하다고 판단됩니다.
print(t.test(df_clean$Mida, df_clean$IPTV, paired = TRUE))
Paired t-test
data: df_clean$Mida and df_clean$IPTV
t = 0.77289, df = 253, p-value = 0.4403
alternative hypothesis: true mean difference is not equal to 0
95 percent confidence interval:
-0.01461916 0.03350585
sample estimates:
mean difference
0.009443343
검정 내용: 정규성이 충족되지 않을 경우를 대비한 비모수적 중앙값 차이 검정.
가설: \(H_0: Median_{diff} = 0\) vs \(H_1: Median_{diff} \neq 0\)
검정 결과: P-value > 0.05
결과 해석: 귀무가설을 기각하지 못했습니다. 비모수적 관점에서도 두 데이터의 분포 위치(Location)에는 유의미한 차이가 없음이 재확인되었습니다.
print(wilcox.test(df_clean$Mida, df_clean$IPTV, paired = TRUE))
Wilcoxon signed rank test with continuity correction
data: df_clean$Mida and df_clean$IPTV
V = 16171, p-value = 0.9857
alternative hypothesis: true location shift is not equal to 0
검정 내용: 원본 차이 데이터(\(D\))가 정규분포를 따르는지 확인.
가설: \(H_0\): 정규분포를 따른다 vs \(H_1\): 따르지 않는다.
검정 결과: P-value < 0.05
결과 해석: 정규성 가성을 만족하지 못합니다.
print(shapiro.test(x))
Shapiro-Wilk normality test
data: x
W = 0.75892, p-value < 2.2e-16
5.1 검정 개요
5.2 가설 설정
귀무가설 (\(H_0\)): 데이터는 정규분포를 따른다.
대립가설 (\(H_1\)): 데이터는 정규분포를 따르지 않는다.
# 5. Log-Difference 정규성 검정
# 로그 차이 계산 (log(A) - log(B))
x_log <- log(df_clean$Mida) - log(df_clean$IPTV)
# Shapiro-Wilk 검정 수행
shapiro_log_result <- shapiro.test(x_log)
print(shapiro_log_result)
Shapiro-Wilk normality test
data: x_log
W = 0.8147, p-value < 2.2e-16
if (shapiro_log_result$p.value < 0.05) {
cat("해석: P-value < 0.05, H0 기각. 로그 차이 데이터는 정규성을 만족하지 않습니다.\n")
} else {
cat("해석: P-value > 0.05, H0 채택. 로그 차이 데이터는 정규성을 만족합니다.\n")
}해석: P-value < 0.05, H0 기각. 로그 차이 데이터는 정규성을 만족하지 않습니다.
5.3 결과 해석
검정 결과: P-value < 0.05 (\(H_0\) 기각)
결과 해석: 원본 데이터와 로그 변환 데이터 모두 정규성 가정을 만족하지 않습니다. 따라서, 이후 진행되는 동등성 분석에서는 로그 변환 없이 원본 데이터를 사용하되, 정규성에 민감하지 않은 방법(Tolerance Interval의 Howe’s Method 등)을 적용합니다.
6.1 검정 개요
6.2 가설 설정
귀무가설 (\(H_{0}\)): 평균 차이가 설정된 범위 밖이다 (\(\mu_{diff} \le -\delta\) 또는 \(\mu_{diff} \ge \delta\)).
대립가설 (\(H_{1}\)): 평균 차이가 설정된 범위 안이다 (\(-\delta < \mu_{diff} < \delta\), 동등함).
# 3. TOST (평균 동등성 검정)
delta_list <- c(0.01, 0.02, 0.0001, 0.05)
for (d in delta_list) {
cat("\nDelta:", d, "\n")
# plot=FALSE로 설정하여 결과 텍스트만 출력
print(t_TOST(x = x, low_eqbound = -d, high_eqbound = d, mu = 0, plot = FALSE))
}
Delta: 0.01
One Sample t-test
The equivalence test was non-significant, t(253) = -0.046, p = 0.48
The null hypothesis test was non-significant, t(253) = 0.773, p = 0.44
NHST: don't reject null significance hypothesis that the effect is equal to zero
TOST: don't reject null equivalence hypothesis
TOST Results
t df p.value
t-test 0.77289 253 0.440
TOST Lower 1.59133 253 0.056
TOST Upper -0.04556 253 0.482
Effect Sizes
Estimate SE C.I. Conf. Level
Raw 0.009443 0.01222 [-0.0107, 0.0296] 0.9
Hedges's g 0.048351 0.06278 [-0.0547, 0.1513] 0.9
Note: SMD confidence intervals are an approximation. See vignette("SMD_calcs").
Delta: 0.02
One Sample t-test
The equivalence test was non-significant, t(253) = -0.86, p = 0.19
The null hypothesis test was non-significant, t(253) = 0.773, p = 0.44
NHST: don't reject null significance hypothesis that the effect is equal to zero
TOST: don't reject null equivalence hypothesis
TOST Results
t df p.value
t-test 0.7729 253 0.440
TOST Lower 2.4098 253 0.008
TOST Upper -0.8640 253 0.194
Effect Sizes
Estimate SE C.I. Conf. Level
Raw 0.009443 0.01222 [-0.0107, 0.0296] 0.9
Hedges's g 0.048351 0.06278 [-0.0547, 0.1513] 0.9
Note: SMD confidence intervals are an approximation. See vignette("SMD_calcs").
Delta: 1e-04
One Sample t-test
The equivalence test was non-significant, t(253) = 0.76, p = 0.78
The null hypothesis test was non-significant, t(253) = 0.773, p = 0.44
NHST: don't reject null significance hypothesis that the effect is equal to zero
TOST: don't reject null equivalence hypothesis
TOST Results
t df p.value
t-test 0.7729 253 0.440
TOST Lower 0.7811 253 0.218
TOST Upper 0.7647 253 0.777
Effect Sizes
Estimate SE C.I. Conf. Level
Raw 0.009443 0.01222 [-0.0107, 0.0296] 0.9
Hedges's g 0.048351 0.06278 [-0.0547, 0.1513] 0.9
Note: SMD confidence intervals are an approximation. See vignette("SMD_calcs").
Delta: 0.05
One Sample t-test
The equivalence test was significant, t(253) = -3.3, p < 0.01
The null hypothesis test was non-significant, t(253) = 0.773, p = 0.44
NHST: don't reject null significance hypothesis that the effect is equal to zero
TOST: reject null equivalence hypothesis
TOST Results
t df p.value
t-test 0.7729 253 0.44
TOST Lower 4.8651 253 < 0.001
TOST Upper -3.3193 253 < 0.001
Effect Sizes
Estimate SE C.I. Conf. Level
Raw 0.009443 0.01222 [-0.0107, 0.0296] 0.9
Hedges's g 0.048351 0.06278 [-0.0547, 0.1513] 0.9
Note: SMD confidence intervals are an approximation. See vignette("SMD_calcs").
6.3 결과 해석
검정 결과: \(\delta=0.01, 0.02\)에서는 기각 실패, \(\delta=0.05\)에서는 기각 성공.
결과 해석: 평균적인 오차는 5%p 이내로 들어오지만, 1~2%p 수준의 엄격한 기준으로는 통계적으로 확실하게 동등하다고 말하기 어렵습니다. 이는 데이터 자체의 변동성(표준편차)이 존재하기 때문입니다.
7.1 검정 개요
검정 내용 및 절차: 데이터 전체가 구조적인 편향(Bias)이나 이상치(Outlier) 없이 **무작위성(Randomness)**을 띠는지 확인하는 Permutation 기반 검정입니다.
Max-Deviation Test: 관측된 최대 편차가 우연히 발생할 수 있는 수준인지 확인합니다.
L2-Energy Test: 전체적인 변동 에너지가 일관된 수준인지 확인합니다.
7.2 가설 설정
귀무가설 (\(H_0\)): 차이 데이터는 대칭적인 랜덤 분포를 따른다 (일관성 있음).
대립가설 (\(H_1\)): 데이터에 구조적인 편향이나 이상치가 존재한다 (일관성 없음).
### ============================================
### 4. Global Equivalence Tests (수정됨)
### ============================================
# Max-Deviation Test (수정된 로직 적용)
global_max_test <- function(x, B = 10000, seed = 42) {
if (!is.null(seed)) set.seed(seed)
T_obs <- max(abs(x - mean(x)))
T_perm <- replicate(B, {
# 원본 데이터 부호 반전 후 편차 계산
x_star <- x * sample(c(-1, 1), length(x), replace = TRUE)
max(abs(x_star - mean(x_star)))
})
list(Test="Max-Deviation", T_obs = T_obs, p_value = mean(T_perm >= T_obs))
}
# L2 Energy Test (수정된 로직 적용)
global_L2_test <- function(x, B = 10000, seed = 42) {
if (!is.null(seed)) set.seed(seed)
T_obs <- sum((x - mean(x))^2)
# Permutation
T_perm <- replicate(B, {
x_star <- x * sample(c(-1, 1), length(x), replace = TRUE)
sum((x_star - mean(x_star))^2)
})
list(Test="L2-Energy", T_obs = T_obs, p_value = mean(T_perm >= T_obs))
}
print(global_max_test(x))$Test
[1] "Max-Deviation"
$T_obs
[1] 1.12388
$p_value
[1] 0.6692
print(global_L2_test(x))$Test
[1] "L2-Energy"
$T_obs
[1] 9.59345
$p_value
[1] 0.5585
7.3 결과 해석
검정 결과: P-value > 0.05 (Max-Deviation \(\approx 0.67\), L2-Energy \(\approx 0.56\))
결과 해석: 귀무가설을 기각하지 못했습니다. 이는 미다팀과 IPTV 간의 차이가 특정 채널에서만 튀거나 왜곡되지 않았으며, 전체적으로 일관된 품질을 유지하고 있음을 강력하게 시사합니다.
8.1 검정 개요
8.2 가설 설정 (두 귀무가설을 모두 기각해야 동등함)
| 가설 종류 | 내용 | 의미 (Containment Logic) |
| 귀무가설 1 (\(H_{10}\)) | \(q_{1-p/2} \le L\) | 상위 꼬리가 목표 하한보다 낮다 |
| 대립가설 1 (\(H_{11}\)) | \(q_{1-p/2} > L\) | 상위 꼬리가 목표 하한보다 높다 (기각해야 함) |
| 귀무가설 2 (\(H_{20}\)) | \(q_{p/2} \ge U\) | 하위 꼬리가 목표 상한보다 크거나 같다 |
| 대립가설 2 (\(H_{21}\)) | \(q_{p/2} < U\) | 하위 꼬리가 목표 상한보다 작다 (기각해야 함) |
# 6. Individual Equivalence Test (Quantile TOST)
# 목표 동등성 경계 설정 (Target Bounds)
Target_L <- -0.5
Target_U <- 0.5
# 허용 구간(Tolerance Interval) 계산
# Howe Method 사용, 정규성 불만족으로 log.norm = FALSE 적용
tol_result <- normtol.int(x = x, alpha = 0.05, P = 0.95, side = 2, method = "HE", log.norm = FALSE)
Calc_L <- tol_result[1, "2-sided.lower"]
Calc_U <- tol_result[1, "2-sided.upper"]
# 결과 출력
cat(sprintf("Calculated 95%% Tolerance Interval: [%.5f, %.5f]\n", Calc_L, Calc_U))Calculated 95% Tolerance Interval: [-0.40336, 0.42225]
cat(sprintf("Target Equivalence Limit : [%.5f, %.5f]\n", Target_L, Target_U))Target Equivalence Limit : [-0.50000, 0.50000]
# 가설 검정 (Hypothesis Testing)
# H10: q_{1-p/2} <= L (하한 검정) -> 기각 시 성공
reject_H10 <- Calc_L >= Target_L
# H20: q_{p/2} >= U (상한 검정) -> 기각 시 성공
reject_H20 <- Calc_U <= Target_U
# 최종 결론 도출
if (reject_H10 && reject_H20) {
cat("\nFinal Result: PASS (Individually Equivalent)\n")
cat(" 계산된 구간이 목표 범위 내에 포함되므로, 두 데이터는 개별 채널 수준에서 동등합니다.\n")
} else {
cat("\nFinal Result: FAIL (Not Equivalent)\n")
cat(" 계산된 구간이 목표 범위를 벗어납니다.\n")
}
Final Result: PASS (Individually Equivalent)
계산된 구간이 목표 범위 내에 포함되므로, 두 데이터는 개별 채널 수준에서 동등합니다.
8.3 결과 해석
검정 결과:
계산된 95% 허용 구간: \([-0.403, 0.422]\)
목표 동등성 경계: \([-0.5, 0.5]\)
판정: 계산된 구간이 목표 경계 내에 완전히 포함되므로, 두 귀무가설 모두 기각 (\(P < 0.05\)).
결과 해석: 통계적으로 전체 채널의 95% 이상이 오차 범위 \(\pm 0.42\%p\) 이내에서 일치함이 입증되었습니다. 따라서, 허용 오차 \(\pm 0.5\%p\) 기준 하에서 미다팀 데이터는 IPTV 데이터와 개별 채널 수준에서 동등하며, 대체 가능합니다.
본 연구는 미다팀 시청률 데이터를 IPTV 데이터로 대체할 수 있는지에 대한 통계적 타당성을 검증하였습니다. 데이터 전처리부터 다각도의 통계 검정을 수행한 최종 결론은 다음과 같습니다.
매핑 신뢰성: 채널명을 Key로 활용한 1:1 매핑을 통해 데이터의 정합성을 확보하였습니다.
데이터 분포: Global Equivalence Test 결과(\(P > 0.05\)), 두 데이터 간의 차이는 특정 채널에 편향되거나 구조적인 이상치(Outlier) 없이 무작위 오차(Random Noise) 수준의 일관성을 유지하고 있음이 확인되었습니다.
평균 동등성 (Mean Equivalence): 전체적인 평균 차이는 0에 매우 근접(0.009)하며, 5%p 수준에서는 동등하지만 1~2%p의 초정밀 기준에서는 차이가 존재할 수 있음을 확인했습니다.
개별 동등성 (Individual Equivalence): 가장 보수적인 기준인 Quantile TOST 수행 결과, 95%의 채널이 \(\pm 0.42\%p\) 이내의 오차를 가지는 것으로 나타났습니다.