[프로젝트 #2-4] EDA 1차 진행 : 단변량/다변량 분석 | 파생변수는 어쩌지...?

심화 프로젝트 4일차(벌써)... 다 같이 전처리 파일로 EDA (1차)를 진행하였다.

 

오늘 내가 진행한 내용

 - host_is_superhost 컬럼으로 슈퍼호스트 여부(슈퍼/일반)에 따른 분포를 알아보고자 시각화 진행.(단변량 분석)

host_id 중복이 있는 데이터(왼)와 중복이 없는 데이터(오)

코드스니펫

더보기
# 1. host_id 기준으로 중복 제거 (첫 번째 행 유지)
df_unique_host = df_pp.drop_duplicates(subset=['host_id'], keep='first')

# 2. 유니크한 호스트들만 있는 데이터프레임에서 슈퍼호스트 여부 분석
print("\n" + "="*60)
print("고유한 host_id 기준으로 슈퍼호스트 분포 분석")
print("="*60)

# 슈퍼호스트 분포 계산
print("\n[호스트의 슈퍼호스트 비율]")
unique_superhost_counts = df_unique_host['host_is_superhost'].value_counts()
print(unique_superhost_counts)

# 비율 출력
superhost_true_count = unique_superhost_counts.get('t', 0) # 't'가 없으면 0으로 처리
total_unique_hosts = unique_superhost_counts.sum()
print(f"\n호스트의 슈퍼호스트 비율: {superhost_true_count / total_unique_hosts * 100:.2f}%")

# 시각화
fig, axes = plt.subplots(1, 2, figsize=(12, 4))

# 슈퍼호스트 비율 파이차트 (axes[0])
# 주의: index 순서에 따라 '일반호스트', '슈퍼호스트', 'Unknown'을 맞춰야 함!
# 보통 value_counts()는 빈도가 높은 순서로 정렬됨.
sorted_labels = ['일반호스트', '슈퍼호스트', 'Unknown'] 
sorted_counts = unique_superhost_counts.reindex(['f', 't', 'unknown']) # index 순서 지정

axes[0].pie(sorted_counts.values, 
            labels=sorted_labels, 
            autopct='%1.1f%%',
            colors=['lightcoral', 'lightgreen', 'grey'], 
            startangle=90)
axes[0].set_title('유니크 호스트 - 슈퍼호스트 비율')

# 슈퍼호스트 분포 막대차트 (axes[1])
axes[1].bar(range(len(unique_superhost_counts)), unique_superhost_counts.values, 
            color=['lightcoral', 'lightgreen', 'grey'], alpha=0.7, edgecolor='black')
axes[1].set_xticks(range(len(unique_superhost_counts)))
axes[1].set_xticklabels(sorted_labels)
axes[1].set_title('유니크 호스트 - 슈퍼호스트 분포')
axes[1].set_ylabel('호스트 수')
axes[1].grid(True, alpha=0.3, axis='y')

plt.tight_layout()
plt.show()

처음 왼쪽 그래프를 뽑아보고서, 문득 중복 데이터가 있지 않을까 하는 생각이 들었다. 호스트 1명이 여러 숙소를 가지고 있을 경우에는 어떻게 처리해야하나? 해서 에어비앤비 규정을 검색! 그 결과 호스트 1명당 하나의 슈퍼호스트 부여 (숙소별 부여 아님) 한다는 사실 확인!

OK! 그러면 host_id 중복 제거 해야해! 그 결과 나온 것이 오른쪽 그래프이다. 큰 차이는 아니지만 그래도 문제 해결!!

 

 

- instant_bookable 컬럼으로 즉시예약 가능여부(가능/불가능)에 따른 분포를 알아보고자 시각화 진행.(단변량 분석)

왼쪽과 같이 그래프가 나옴.
이 데이터는 슈퍼호스트와는 달리 숙소 기준이기 때문에 중복값이 있을 수 없다. 그래서 이대로 확인.

🔍 즉시예약이 불가한 숙소가 약 3배 정도 더 많다는 사실 확인

 

 

- amenities 컬럼에는 각 숙소에 비치되어 있는 어메니티가 리스트 형태로 값이 들어가 있어서, 이를 수치화(어메니티 수)를 시도.

df_pp['amenities_cnt'] = df_pp['amenities_list'].apply(lambda x: len(x))
print(df_pp[['amenities_list', 'amenities_cnt']].head())

어메니티 수로 변환 시도 결과

따라서, 어메니티 수와 가격(log) 데이터를 함께 뽑아볼 수 있겠다고 생각 : 연속형 X 연속형 -> scatterplot

코드스니펫

더보기
# 수치 x 수치 : 어메니티 수와 가격(log) ✅
sample_data = df_pp.sample(5000, random_state=42)
sns.scatterplot(data=sample_data, x='amenities_cnt', y='price_log', hue='room_type', alpha=0.6)
plt.title("어메니티 수 x 가격(log) 산점도 (by room_type)")
plt.tight_layout()
plt.show()

음, 뭐 대단한 인사이트는 아니라도 확인해 볼 수 있는 건 있었다.

1. private room의 가격대보다 entire home/apt의 가격대가 높은점 (둘다 어메니티 수 범위는 큼)

2. hotel room의 경우에는 가격이 높건 낮건 간에 비교적 일정한 어메니티 수를 보유

 

➡️ 어메니티 관련 컬럼은 사용하지 않기로 결정,,,!! 

 

 

- Room_type 및 accommodates(수용인원)별 평균 가격 을 확인해보고 싶어졌다.

코드스니펫

더보기
# [Room Type 및 수용 인원별 평균 가격]을 확인해보자.
room_accommodates_mean_price = df_pp.groupby(['room_type', 'accommodates'])['price_log'].mean().reset_index(name='mean_price')
room_accommodates_mean_price

# lineplot을 그려보고 싶은데!!
plt.figure(figsize=(10,6))

# accommodates를 x축, mean_price를 y축 : room_type별로 라인을 구분하여 그림
sns.lineplot(
    data=room_accommodates_mean_price,
    x='accommodates',
    y='mean_price',
    hue='room_type',
    marker='o'
)

plt.title("Room Type 및 수용 인원별 평균 가격")
plt.xlabel("수용 인원 (accommodates)")
plt.ylabel("평균 가격 (log)")
plt.grid(True, linestyle='--', alpha=0.7)
plt.legend(title='Room Type')
plt.show()

LinePlot

이렇게 뽑아보았는데, 무엇을 확인해볼 수 있지??... hmmm

1. 대부분의 Room Type에서 수용인원이 높을수록 평균가격도 올라가는 추세를 보이긴 함.

2. shared room은 6인 초과하는 숙소는 없음

3. private room은 10명 13명에서 높게 나타났는데, 방해받지 않는 파티룸 같은 것이지 않을까?

 

➡️ 해석이 어렵다는 것은 유의미한 정보는 아닐 가능성이 높다는 의견이 있었음. 차라리 잘됐어!!

 

 

팀 결정사항 및 결론

1. [데이터 정규화 : 머신러닝까지 이어진다면 반드시 필요한 과정]

- 수치형 데이터 : price 가격 컬럼을 정규화를 통해 범위를 줄이고, 정규분포에 맞게 log변환함.

- 범주형 데이터 

▼ 참고글

 

2. [property_type 컬럼의 고유값이  57개 정도가 있는데, 이것을 그룹화하여 값들을 줄여보자]

이거는 같은 묶음으로 볼 수 있는 values들을 묶음처리 하는 과정(즉, 대표군으로 묶음)을 거쳤다. 이 과정 언급은 생략...

 

 

3. [amenities 컬럼의 values를 분류하여 분석에 이용할 수 있지 않을까? 싶은 생각으로 들여다보기 시작했음]

하지만, 너무 많은 amenities.values()가 존재하고 세밀하게 쪼개져 있어서 어떤 걸 포함하고 있다고해서 그것이 가격에 영향을 미친다는 것을 증명해 내기 어렵다고 판단. ➡️ amenities는 분석에서 DROP !

 

 

오늘의 회고

어떤 목적을 가지고 분석을 진행할 것이냐를 생각해보았을 때, 전처리 마지막 부분에서 어떤 파생변수를 만들어서 분석으로 이어가느냐를 계속 고민을 해봐도 도저히 답이 안나왔다. 이에 대해서 튜터님께 고민을 이야기를 했고, 당연한 것이라는 말씀을 해주셨다. 당연히 도메인 지식을 모르기 때문에 생각나는 게 없을 거라는 답변을 주셨고 조금이나마 위로가 되어서 답답한 마음은 넣어두기로 했다.

대신에 도메인에 대한 자료나 정보를 많이 찾아보는 것을 권유해주셨다. 맞는 말이다! 도메인 지식을 모르는데, 파생변수를 만들어 낼 수가 없지...💭

 

TIP. 파생변수를 만들때는 두 변수의 상관계수를 찍어보고, 그 값이 높은 것을 가지고 파생변수를 만들어야 한다.
      💡df[['컬럼1, '컬럼2']].corr()

 

내일 할 거

- EDA 2차 진행

- 통계를 진행할 가설 선정 및 일단 해봐. 그냥 해봐.

 

끝.