① 주어진 데이터를 이용하여 이동시간(출동시간과 도착시간의 차이)이 평균적으로 가장 오래 걸린 구급대의 이동시간을 구하시오. (분 단위로 환산 및 반올림하여 정수로 출력)
② 주어진 데이터를 이용하여 교수 1인당 맡고 있는 학생 수가 가장 많은 대학교를 찾고, 그 대학교의 전체 교수의 수를 구하시오. (정수로 출력)
③ 주어진 데이터를 이용하여 연도별 총 범죄 건수의 월평균 값을 구하고, 그 값이 가장 큰 연도의 총 범죄 건수의 월평균 값을 집계하시오. (반올림하여 정수로 출력)
import pandas as pd
# CSV 파일 불러오기
url = 'https://raw.githubusercontent.com/YoungjinBD/dataset/main/data_6_1_1.csv'
df = pd.read_csv(url)
# 시간 데이터 변환 및 이동시간 계산
df['출동시간'] = pd.to_datetime(df['출동시간'])
df['도착시간'] = pd.to_datetime(df['도착시간'])
df['이동시간'] = (df['도착시간'] - df['출동시간']).dt.total_seconds() / 60
# 구급대별 평균 이동시간 계산 및 최대값 추출
group_mean = df.groupby('구급대')['이동시간'].mean()
max_time = round(group_mean.max(), 2)
# 결과 출력
print(df.head())## 구급대 출동시간 도착시간 이동시간
## 0 구급대8 2020-07-10 06:11:45 2020-07-10 06:52:06 40.350000
## 1 구급대9 2020-07-13 06:12:21 2020-07-13 07:58:59 106.633333
## 2 구급대1 2020-07-06 06:12:29 2020-07-06 07:51:55 99.433333
## 3 구급대5 2020-07-21 06:11:41 2020-07-21 08:08:36 116.916667
## 4 구급대1 2020-07-29 06:12:00 2020-07-29 07:24:21 72.350000
##
## 구급대별 평균 이동시간:
## 구급대
## 구급대1 54.952381
## 구급대10 42.365000
## 구급대2 60.228571
## 구급대3 43.490741
## 구급대4 49.136667
## 구급대5 61.250000
## 구급대6 41.764583
## 구급대7 83.337037
## 구급대8 42.693750
## 구급대9 80.658889
## Name: 이동시간, dtype: float64
##
## 이동시간 중 최대값: 83.34
import pandas as pd
# csv 파일 불러오기
df = pd.read_csv('https://raw.githubusercontent.com/YoungjinBD/dataset/main/data_6_1_2.csv')
print(df.head())## 대학교명 교수 경영학과 경제학과 컴퓨터공학과 산업공학과 국문학과 영문학과
## 0 대학교1 20 121 72 158 131 77 59
## 1 대학교2 31 178 139 145 137 63 90
## 2 대학교3 23 136 139 154 111 91 50
## 3 대학교4 32 72 136 67 51 133 159
## 4 대학교5 22 61 73 86 82 55 124
import pandas as pd
# 전체 학생 수 계산
df['학생'] = df.iloc[:, 2:].sum(axis=1)
# 학생/교수 비율 계산
df['학생/교수'] = df['학생'] / df['교수']
# 최대 학생/교수 비율을 가진 대학의 교수 수
max_id = df['학생/교수'].idxmax() # '학생/교수' 열에서 최대값을 가진 인덱스를 찾음
univ = df.at[max_id, '대학교명']
result = df.at[max_id, '교수'] # .at 사용으로 더 효율적인 값 추출
# 결과 출력
print(df.head()) # 데이터프레임 일부 확인## 대학교명 교수 경영학과 경제학과 컴퓨터공학과 산업공학과 국문학과 영문학과 학생 학생/교수
## 0 대학교1 20 121 72 158 131 77 59 618 30.900000
## 1 대학교2 31 178 139 145 137 63 90 752 24.258065
## 2 대학교3 23 136 139 154 111 91 50 681 29.608696
## 3 대학교4 32 72 136 67 51 133 159 618 19.312500
## 4 대학교5 22 61 73 86 82 55 124 481 21.863636
##
## 최대 학생/교수 비율 대학 : 대학교46
##
## 최대 학생/교수 비율 대학의 교수 수 : 22
import pandas as pd
# CSV 파일 불러오기
url = 'https://raw.githubusercontent.com/YoungjinBD/dataset/main/data_6_1_3.csv'
df = pd.read_csv(url)
# 총 범죄 건수 계산
df['총범죄건수'] = df.iloc[:, 1:-1].sum(axis=1)
# 연도 추출
df['연도'] = df['날짜'].str[:4]
# 연도별 총 범죄 건수 평균 계산 및 최대값 추출
group_mean = df.groupby('연도')['총범죄건수'].mean()
result = round(group_mean.max())
# 결과 출력
print("연도별 평균 총 범죄 건수:")## 연도별 평균 총 범죄 건수:
## 연도
## 2018 527.333333
## 2019 520.500000
## 2020 514.916667
## 2021 528.333333
## 2022 524.416667
## Name: 총범죄건수, dtype: float64
##
## 최대 평균 총 범죄 건수: 528
아래는 학생들의 생활패턴과 신체, 거주지역 등에 대한 데이터이다.
| 일평균수면시간 | 일평균학습시간 | 일평균스마트폰사용시간 | 키 | 몸무게 | 체격 | 기초대사량 | 거주지역 | 구분 |
|---|---|---|---|---|---|---|---|---|
| 1 | 7.35 | 7.74 | 4.8 | Tall | 52.05 | L | 1499.4 | 동구 |
| 2 | 7.05 | 8.1 | 1.2 | Tall | 51.3 | M | 1624.4 | 서구 |
| 3 | 7.35 | 7.74 | 1.2 | Tall | 51.285 | L | 1499.4 | 동구 |
| 4 | 8.58 | 5.76 | 4.8 | Short | 25.545 | XS | 1249.5 | 서구 |
| 일평균수면시간 | 일평균학습시간 | 일평균스마트폰사용시간 | 키 | 몸무게 | 체격 | 기초대사량 | 거주지역 |
|---|---|---|---|---|---|---|---|
| 1 | 7.97 | 7.11 | 1.2 | Tall | 51.375 | L | 1749.3 |
| 2 | 9.8 | 5.76 | 1.2 | Short | 28.71 | XS | 1749.3 |
| 3 | 7.66 | 7.38 | 1.2 | Tall | 36.915 | L | 1624.4 |
| 4 | 9.5 | 5.94 | 3.0 | Short | 24.045 | XS | 1624.4 |
학생 530명에 대한 학습용(train) 데이터를 이용하여 학생 구분(유치원생, 초등학생, 중학생, 고등학생, 대학생) 예측 모델을 만든 후, 이를 평가용(test) 데이터에 적용하여 얻은 230명 학생의 구분을 다음과 같은 형식의 CSV 파일로 생성하시오.
(제출한 모델의 성능은 f1-macro 평가에 따라 채점)
| 구분예측 |
|---|
| 중학생 |
| 초등학생 |
| 대학생 |
| 고등학생 |
import pandas as pd
# csv 파일 불러오기
train_df = pd.read_csv('https://raw.githubusercontent.com/YoungjinBD/dataset/main/data_6_2_train.csv')
test_df = pd.read_csv('https://raw.githubusercontent.com/YoungjinBD/dataset/main/data_6_2_test.csv')
print(train_df)## 일평균수면시간 일평균학습시간 일평균스마트폰사용시간 키 몸무게 체격 기초대사량 거주지역 구분
## 0 7.35 7.74 4.8 Tall 52.050 L 1499.4 동구 고등학생
## 1 7.05 8.10 1.2 Tall 51.300 M 1624.4 서구 중학생
## 2 7.35 7.74 3.0 Tall 51.285 L 1499.4 동구 고등학생
## 3 8.58 6.66 4.8 Short 25.545 XS 1249.5 서구 초등학생
## 4 7.05 8.10 4.8 Tall 54.150 M 1624.4 서구 대학생
## .. ... ... ... ... ... .. ... ... ...
## 525 10.11 5.58 4.8 Short 25.185 XS 1874.3 동구 초등학생
## 526 8.27 6.84 1.2 Tall 51.165 M 2124.2 동구 고등학생
## 527 7.35 7.74 1.2 Tall 40.995 L 1499.4 동구 중학생
## 528 10.11 5.58 0.0 Short 18.330 XS 1874.3 동구 유치원생
## 529 6.44 8.82 3.0 Tall 44.535 S 1499.4 동구 고등학생
##
## [530 rows x 9 columns]
## 일평균수면시간 일평균학습시간 일평균스마트폰사용시간 키 몸무게 체격 기초대사량 거주지역
## 0 7.97 7.11 1.2 Tall 51.375 L 1749.3 북구
## 1 9.80 5.76 1.2 Short 28.710 XS 1749.3 북구
## 2 7.66 7.38 1.2 Tall 36.915 L 1624.4 남구
## 3 9.50 5.94 3.0 Short 24.045 XS 1624.4 동구
## 4 6.44 8.82 3.0 Tall 45.180 S 1499.4 서구
## .. ... ... ... ... ... .. ... ...
## 225 9.80 5.76 3.0 Short 30.195 XS 1749.3 북구
## 226 8.58 6.66 4.8 Short 25.875 XS 1249.5 동구
## 227 8.27 6.84 1.2 Tall 50.460 M 2124.2 남구
## 228 7.66 7.38 4.8 Tall 48.645 L 1624.4 북구
## 229 9.80 5.76 4.8 Short 33.375 XS 1749.3 남구
##
## [230 rows x 8 columns]
## <class 'pandas.core.frame.DataFrame'>
## RangeIndex: 530 entries, 0 to 529
## Data columns (total 9 columns):
## # Column Non-Null Count Dtype
## --- ------ -------------- -----
## 0 일평균수면시간 530 non-null float64
## 1 일평균학습시간 530 non-null float64
## 2 일평균스마트폰사용시간 530 non-null float64
## 3 키 530 non-null object
## 4 몸무게 530 non-null float64
## 5 체격 530 non-null object
## 6 기초대사량 530 non-null float64
## 7 거주지역 530 non-null object
## 8 구분 530 non-null object
## dtypes: float64(5), object(4)
## memory usage: 37.4+ KB
## 기초 통계 정보:
## 키 체격 거주지역 구분
## count 530 530 530 530
## unique 2 4 4 5
## top Tall XS 남구 유치원생
## freq 277 253 145 140
##
## 결측치 개수:
## 일평균수면시간 0
## 일평균학습시간 0
## 일평균스마트폰사용시간 0
## 키 0
## 몸무게 0
## 체격 0
## 기초대사량 0
## 거주지역 0
## 구분 0
## dtype: int64
##
## 타겟 값 분포:
## 구분
## 유치원생 140
## 초등학생 121
## 고등학생 120
## 대학생 78
## 중학생 71
## Name: count, dtype: int64
## 테스트 데이터 타입 정보:
## <class 'pandas.core.frame.DataFrame'>
## RangeIndex: 230 entries, 0 to 229
## Data columns (total 8 columns):
## # Column Non-Null Count Dtype
## --- ------ -------------- -----
## 0 일평균수면시간 230 non-null float64
## 1 일평균학습시간 230 non-null float64
## 2 일평균스마트폰사용시간 230 non-null float64
## 3 키 230 non-null object
## 4 몸무게 230 non-null float64
## 5 체격 230 non-null object
## 6 기초대사량 230 non-null float64
## 7 거주지역 230 non-null object
## dtypes: float64(5), object(3)
## memory usage: 14.5+ KB
##
## 기초 통계 정보 (문자열 열):
## 키 체격 거주지역
## count 230 230 230
## unique 2 4 4
## top Short XS 북구
## freq 126 126 74
##
## 결측치 개수:
## 일평균수면시간 0
## 일평균학습시간 0
## 일평균스마트폰사용시간 0
## 키 0
## 몸무게 0
## 체격 0
## 기초대사량 0
## 거주지역 0
## dtype: int64
# 학습용 데이터의 타겟 값 처리
targetVal = train_df.pop('구분')
# 학습용/테스트용 데이터의 인코딩 진행
print(train_df.shape, test_df.shape)## (530, 8) (230, 8)
train_df = pd.get_dummies(train_df)
test_df = pd.get_dummies(test_df)
print(train_df.shape, test_df.shape)## (530, 15) (230, 15)
from sklearn.model_selection import train_test_split
train_x, validation_x, train_y, validation_y = train_test_split(train_df, targetVal, test_size=0.2, random_state=0)
print(train_x.shape, validation_x.shape, train_y.shape, validation_y.shape)## (424, 15) (106, 15) (424,) (106,)
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import f1_score, accuracy_score
# 랜덤 포레스트 분류 모델 생성
rfc = RandomForestClassifier(n_estimators=200, max_depth=10, random_state=0)
# 모델 학습
rfc.fit(train_x, train_y)RandomForestClassifier(max_depth=10, n_estimators=200, random_state=0)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
RandomForestClassifier(max_depth=10, n_estimators=200, random_state=0)
# 학습 정확도 출력
train_pred = rfc.predict(train_x)
train_f1 = f1_score(train_y, train_pred, average='macro')
print(f"학습 데이터 F1 점수: {train_f1:.4f}")## 학습 데이터 F1 점수: 0.9975
# 검증 데이터 예측 및 F1 점수 계산
validation_pred = rfc.predict(validation_x)
validation_f1 = f1_score(validation_y, validation_pred, average='macro')
validation_acc = accuracy_score(validation_y, validation_pred)
print(f"검증 데이터 F1 점수: {validation_f1:.4f}")## 검증 데이터 F1 점수: 0.9087
## 검증 데이터 정확도: 0.9245
## 테스트 데이터 예측 시작...
prediction_test = rfc.predict(test_df)
# 예측 결과를 데이터프레임으로 변환
result = pd.DataFrame({'pred': prediction_test})
# 예측 결과 출력
print("예측 결과:")## 예측 결과:
## pred
## 0 고등학생
## 1 초등학생
## 2 중학생
## 3 유치원생
## 4 고등학생
## 예측 결과가 'result.csv'에 저장되었습니다.
주어진 데이터를 이용하여 항암제를 투여받은 환자들의 부작용 분포와 감기약을 투여받은 환자들의 부작용 분포 간 차이가 있는지 확인하시오.
데이터
항암제 투여 환자들의 관찰된 부작용
[무증상, 속쓰림, 무증상, 무증상, 무증상, 조금아픔, 무증상,
조금아픔, 무증상, 조금아픔, 무증상, 아픔, 무증상, 조금아픔,
무증상, 아픔, 무증상, 속쓰림, 무증상, 아픔, 무증상]
감기약 투여 환자들의 부작용 발생 비율
귀무가설(\(H_0\)) : 감기약의 부작용과 항암제의 부작용은 동일하다.
대립가설(\(H_1\)) : 감기약의 부작용과 항암제의 부작용은 다르다.
① 항암제 투여 환자들 중 ‘무증상’ 비율을 0과 1 사이로 구하시오.
② 감기약의 부작용 비율과 항암제의 부작용 관찰 값이 통계적으로 유의미하게 차이가 있는지 카이제곱 검정을 이용하여 검정 통계를 구하시오.
③ 위의 p-value를 구하시오.
주어진 데이터를 이용하여 다중선형회귀 문제를 해결하시오.
데이터 : data_6_3_2.csv
| Ozone | Solar | Wind | Temp | Month | Day |
|---|---|---|---|---|---|
| 1 | 41 | 190 | 7.4 | 67 | 5 |
| 2 | 36 | 118 | 7.4 | 72 | 5 |
| 3 | 12 | 149 | 12.6 | 74 | 5 |
| 4 | 18 | 313 | 11.5 | 62 | 5 |
| … | … | … | … | … | … |
| 153 | 20 | 223 | 11.5 | 68 | 9 |
① 선형회귀 모델을 만들어 독립변수 Ozone의 회귀계수(regression
coefficient)를 구하시오.
- 독립변수 : Solar(태양 에너지), Wind(바람의 세기), Ozone(오존
농도)
- 종속변수 : Temp(온도)
② Solar와 Ozone은 고정, Wind가 증가함에 따라 Temp가 감소하는지 검증하기 위한 다중선형회귀 분석을 수행하여 Wind의 회귀계수에 대한 p-value를 구하시오. (유의수준 0.05)
③ Solar가 150, Wind가 7.5, Ozone이 45일 경우, 예측 값과 그에 대한 95% 신뢰구간을 구하시오.
import pandas as pd
# 주어진 데이터를 입력
df = pd.DataFrame({"항암제" : ['무증상', '속쓰림', '무증상', '무증상', '조금아픔', '무증상', '조금아픔', '무증상', '조금아픔', '무증상', '아픔', '무증상', '조금아픔', '무증상', '아픔', '무증상', '속쓰림', '무증상', '아픔', '무증상']})
print(df)## 항암제
## 0 무증상
## 1 속쓰림
## 2 무증상
## 3 무증상
## 4 조금아픔
## 5 무증상
## 6 조금아픔
## 7 무증상
## 8 조금아픔
## 9 무증상
## 10 아픔
## 11 무증상
## 12 조금아픔
## 13 무증상
## 14 아픔
## 15 무증상
## 16 속쓰림
## 17 무증상
## 18 아픔
## 19 무증상
# 항암제 열의 비율 계산
total = len(df)
cnt_no_symptoms = df['항암제'].value_counts(normalize=True)['무증상']
# 결과 출력
print(f"'무증상' 비율: {cnt_no_symptoms:.2f}")## '무증상' 비율: 0.55
##
## 각 카테고리 비율:
## 항암제
## 무증상 0.55
## 조금아픔 0.20
## 아픔 0.15
## 속쓰림 0.10
## Name: proportion, dtype: float64
##
## 각 카테고리 개수:
## 항암제
## 무증상 11
## 조금아픔 4
## 아픔 3
## 속쓰림 2
## Name: count, dtype: int64
import scipy.stats as stats
# 관측값 계산
observed = df['항암제'].value_counts().to_list()
# 기대값 정의
total = len(df)
expected = [0.7 * total, 0.1 * total, 0.05 * total, 0.15 * total]
# 카이제곱 검정
statistic, pvalue = stats.chisquare(observed, expected)
# 결과 출력
print(f"카이제곱 통계량: {statistic:.2f}")## 카이제곱 통계량: 6.98
## p-value: 0.073
## 결론: 기대 분포와의 차이는 유의미하지 않습니다.
카이제곱 검정(적합도 검정) 귀무가설(H₀)과 대립가설(H₁)
1. 귀무가설 (H₀)
항암제의 관측 분포는 가정된 기대 분포(70%, 10%, 5%, 15%)와
유의미한 차이가 없다.
즉, 관측된 데이터는 기대 값과 통계적으로 일치한다고 볼 수 있습니다.
2. 대립가설 (H₁)
항암제의 관측 분포는 가정된 기대 분포(70%, 10%, 5%, 15%)와
유의미한 차이가 있다.
즉, 관측된 데이터는 기대 값과 통계적으로 다르다고 볼 수 있습니다.
import pandas as pd
from statsmodels.formula.api import ols
# 데이터 불러오기
url = 'https://raw.githubusercontent.com/YoungjinBD/dataset/main/data_6_3_2.csv'
df = pd.read_csv(url)
# 회귀 분석
formula = "Temp ~ Solar + Wind + Ozone"
model = ols(formula, data=df).fit()
# 결과 확인
print("회귀 계수 (Ozone):", model.params['Ozone'])## 회귀 계수 (Ozone): 0.17196604197981563
##
## p-value (Wind): 0.16909868598497724
## OLS Regression Results
## ==============================================================================
## Dep. Variable: Temp R-squared: 0.500
## Model: OLS Adj. R-squared: 0.486
## Method: Least Squares F-statistic: 35.65
## Date: 토, 01 2 2025 Prob (F-statistic): 4.73e-16
## Time: 13:30:56 Log-Likelihood: -368.79
## No. Observations: 111 AIC: 745.6
## Df Residuals: 107 BIC: 756.4
## Df Model: 3
## Covariance Type: nonrobust
## ==============================================================================
## coef std err t P>|t| [0.025 0.975]
## ------------------------------------------------------------------------------
## Intercept 72.4186 3.216 22.522 0.000 66.044 78.793
## Solar 0.0073 0.008 0.948 0.345 -0.008 0.022
## Wind -0.3229 0.233 -1.384 0.169 -0.785 0.139
## Ozone 0.1720 0.026 6.516 0.000 0.120 0.224
## ==============================================================================
## Omnibus: 6.409 Durbin-Watson: 1.170
## Prob(Omnibus): 0.041 Jarque-Bera (JB): 6.615
## Skew: -0.591 Prob(JB): 0.0366
## Kurtosis: 2.817 Cond. No. 1.05e+03
## ==============================================================================
##
## Notes:
## [1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
## [2] The condition number is large, 1.05e+03. This might indicate that there are
## strong multicollinearity or other numerical problems.
# 새로운 데이터 예측
new_data = pd.DataFrame({'Ozone': [45], 'Solar': [150], 'Wind': [7.5]})
prediction = model.get_prediction(new_data)
summary = prediction.summary_frame(alpha=0.05)
print("\n예측 요약 결과:")##
## 예측 요약 결과:
## mean mean_se ... obs_ci_lower obs_ci_upper
## 0 78.826312 0.864464 ... 65.171661 92.480964
##
## [1 rows x 6 columns]
유의미한 변수:
Ozone은 온도에 유의미한 영향을 미치는 유일한 변수로
확인되었습니다.
반면, Solar와 Wind는 통계적으로 유의미하지 않았습니다.
모델 적합성:
R-squared 값은 0.500으로, 온도의 변동성 중 약 절반을 설명합니다.
잔차가 정규성을 따르지 않을 가능성 및 다중 공선성 문제를 개선할 필요가 있습니다.
실제 활용: