<aside> 📌 Task : 가설 설정
</aside>
귀무가설 (H₀) 상위 25% 숙소(우수 숙소)의 월 예상 매출과 하위 25% 숙소(비우수 숙소)의 월 예상 매출은 같다.
대립가설 (H₁) 상위 25% 숙소(우수 숙소)의 월 예상 매출과 하위 25% 숙소(비우수 숙소)의 월 예상 매출은 같다.
expected_monthly_revenue 등 컬럼 활용<aside> ➕
두 집단을 추가로 비교 분석할 수 있는 컬럼
<aside> 📌 가설 검증
</aside>
<aside> ❓
combinations = [
('도심', 'Entire home/apt'),
('도심', 'Private room'),
('도심', 'Shared room'),
('외곽', 'Entire home/apt'),
('외곽', 'Private room'),
('외곽', 'Shared room'),
]
results = []
for city_and_suburb, room in combinations:
subset = df_filtered[
(df_filtered['city_and_suburb'] == city_and_suburb) &
(df_filtered['room_type'] == room)
]
# 조합별 25%, 75% 사분위수
q1 = subset['popularity_score'].quantile(0.25)
q3 = subset['popularity_score'].quantile(0.75)
# 상위/하위 25%
upper = subset[subset['popularity_score'] >= q3]['expected_monthly_revenue']
lower = subset[subset['popularity_score'] <= q1]['expected_monthly_revenue']
# 결과 저장
results.append({
'조합': f"{city_and_suburb} & {room}",
'전체 수': len(subset),
'상위 25% 수': len(upper),
'하위 25% 수': len(lower),
'상위 25% 월 매출 중앙값': round(upper.median(), 2),
'하위 25% 월 매출 중앙값': round(lower.median(), 2),
'상위 25% 월 매출 평균': round(upper.mean(), 2),
'하위 25% 월 매출 평균': round(lower.mean(), 2)
})
expected_monthly_revenue_25 = pd.DataFrame(results)
expected_monthly_revenue_25

plt.figure(figsize=(10, 6))
# 데이터를 long-format으로 만들어야 seaborn에서 그리기 좋음
melted = expected_monthly_revenue_25.melt(
id_vars='조합',
value_vars=['상위 25% 월 매출 중앙값', '하위 25% 월 매출 중앙값'],
var_name='그룹',
value_name='중앙값'
)
sns.barplot(data=melted, x='조합', y='중앙값', hue='그룹')
plt.xticks(rotation=45)
plt.title('조합별 상위/하위 25% 월 매출 중앙값 비교')
plt.ylabel('월 매출 중앙값')
plt.xlabel('')
plt.tight_layout()
plt.show()

melted = expected_monthly_revenue_25.melt(
id_vars='조합',
value_vars=['상위 25% 월 매출 중앙값', '하위 25% 월 매출 중앙값', '상위 25% 월 매출 평균', '하위 25% 월 매출 평균'],
var_name='그룹',
value_name='월 매출'
)
# 지표종류 파생
melted['지표'] = melted['그룹'].apply(lambda x: '평균' if '평균' in x else '중앙값')
melted['상하위'] = melted['그룹'].apply(lambda x: '상위' if '상위' in x else '하위')
plt.figure(figsize=(12, 6))
sns.lineplot(
data=melted,
x='조합',
y='월 매출',
hue='상하위',
style='지표',
markers=True
)
plt.xticks(rotation=45)
plt.title('상위/하위 25% 월 매출 (평균/중앙값)')
plt.ylabel('예상 월 매출')
plt.xlabel('')
plt.tight_layout()
plt.show()

from scipy.stats import shapiro, levene, ttest_ind, mannwhitneyu
combinations = [
('도심', 'Entire home/apt'),
('도심', 'Private room'),
('도심', 'Shared room'),
('외곽', 'Entire home/apt'),
('외곽', 'Private room'),
('외곽', 'Shared room'),
]
results = []
for city_and_suburb, room in combinations:
subset = df_filtered[
(df_filtered['city_and_suburb'] == city_and_suburb) &
(df_filtered['room_type'] == room)
]
# 조합별 25%, 75% 사분위수
q1 = subset['popularity_score'].quantile(0.25)
q3 = subset['popularity_score'].quantile(0.75)
# 상위/하위 25%
upper = subset[subset['popularity_score'] >= q3]['expected_monthly_revenue']
lower = subset[subset['popularity_score'] <= q1]['expected_monthly_revenue']
# 정규성
s_upper = shapiro(upper)
s_lower = shapiro(lower)
# 등분산성
lev = levene(upper, lower)
# 검정
if s_upper.pvalue > 0.05 and s_lower.pvalue > 0.05:
test_type = 't-test'
t_stat, p_val = ttest_ind(upper, lower, equal_var=(lev.pvalue > 0.05))
else:
test_type = 'Mann-Whitney'
u_stat, p_val = mannwhitneyu(upper, lower, alternative='greater')
# 저장
results.append({
'조합': f"{city_and_suburb} & {room}",
'전체 수': len(subset),
'상위 수': len(upper),
'하위 수': len(lower),
'상위 평균': round(upper.mean(), 2),
'하위 평균': round(lower.mean(), 2),
'상위 중앙값': round(upper.median(), 2),
'하위 중앙값': round(lower.median(), 2),
'정규성 상위 p': round(s_upper.pvalue, 4),
'정규성 하위 p': round(s_lower.pvalue, 4),
'등분산 p': round(lev.pvalue, 4),
'검정': test_type,
'p-value': round(p_val, 5)
})
test_result = pd.DataFrame(results)
test_result

<aside> 👉🏻
p-value가 유의수준인 0.05보다 작은 0에 가까운 숫자이니 귀무가설 기각! 대립가설 채택!
"상위 25% 숙소는 하위 25% 숙소보다 월 예상 매출이 통계적으로 유의하게 높다.”
</aside>
<aside> 💡
1️⃣ 평균과 중앙값의 차이 ⬆️
➖ 평균은 이상치의 영향을 크게 받으니 중앙값 기준으로 보면 좋을 듯!
2️⃣ 상위와 하위의 예상 월 매출 차이 ⬆️⬆️⬆️
➖ 도심 + 전체실 격차가 가장 큼
→ 상위 숙소일수록 + 전체실일 때 수익 높은 편
= 예상 월 매출은 접근성(도심)과 객실의 독립성(전체실)이 중요
3️⃣ 상/하위 모두 공유실의 예상 월 매출이 낮음
➖ 공유실은 데이터가 상/하위 도심: 92개 & 외곽 119개로 값이 너무 적기 때문이라 판단
4️⃣ 도심과 외곽 중 도심의 가격대가 전부 높음
→ 접근성이 주는 요소가 크다고 볼 수 있음
</aside>
</aside>
<aside> ❓
<aside> 1️⃣
</aside>
# 도심 & Entire home/apt 만 필터링
subset = df_filtered[
(df_filtered['city_and_suburb'] == '도심') &
(df_filtered['room_type'] == 'Entire home/apt')
]
# 상위/하위 25% popularity_score 기준
q1 = subset['popularity_score'].quantile(0.25)
q3 = subset['popularity_score'].quantile(0.75)
upper = subset[subset['popularity_score'] >= q3]
lower = subset[subset['popularity_score'] <= q1]
results = {
'지표': [],
'상위 25% 평균': [],
'하위 25% 평균': [],
'상위 25% 중앙값': [],
'하위 25% 중앙값': []
}
columns_to_compare = [
'price',
'expected_monthly_revenue',
'number_of_reviews',
'reviews_per_month',
'availability_365',
'minimum_nights',
'calculated_host_listings_count',
'operating_months'
]
for col in columns_to_compare:
results['지표'].append(col)
results['상위 25% 평균'].append(round(upper[col].mean(), 2))
results['하위 25% 평균'].append(round(lower[col].mean(), 2))
results['상위 25% 중앙값'].append(round(upper[col].median(), 2))
results['하위 25% 중앙값'].append(round(lower[col].median(), 2))
comparison_table = pd.DataFrame(results)
comparison_table

<aside> 💡
1️⃣ price와 expected_monthly_revenue 컬럼을 봤을 때!
평균 가격이나 중앙값으로는 상/하위의 큰 차이가 있다고 보기 어려움
근데 상위 25%가 하위 25%보다 월 예상 매출이 약 10배 높음
→ 가격이 높아도 사람들이 잘 이용하므로 가격을 낮추는 것을 방안으로 내세우기 어려움
2️⃣ number_of_reviews & rivews_per_month 컬럼을 봤을 때!
전체 리뷰 수는 상위 25%가 약 9-10배로 월등히 높음
한 달 평균 리뷰 수는 하위 25%가 거의 없는 수준
→ 하위 25%의 리뷰를 올리는 방안 모색 필요 O
⭐️ 최근 날짜와 함께 비교할 필요 O
3️⃣ availavility 365 컬럼을 봤을 때!
<aside>
<7일 이하 (단기)>

</aside>
4️⃣ minimum_nights 컬럼을 봤을 때!
5️⃣ calculated_host_listings_count 컬럼을 봤을 때!

6️⃣ operating_months 컬럼을 봤을 때!
</aside>
<aside> 📌 추가 분석
</aside>
*제가 메인으로 세운 가설이 너무 당연하게 나와서…! ㅜ 우수 비우수를 컬럼별로 저희가 세운 기준에 맞춰 분석을 추가로 해보고 있습니다!
<aside> ❓
</aside>