제 1 유형


① 주어진 데이터를 이용하여 이동시간(출동시간과 도착시간의 차이)이 평균적으로 가장 오래 걸린 구급대의 이동시간을 구하시오. (분 단위로 환산 및 반올림하여 정수로 출력)

  • 데이터 : data_6_1_1.csv

② 주어진 데이터를 이용하여 교수 1인당 맡고 있는 학생 수가 가장 많은 대학교를 찾고, 그 대학교의 전체 교수의 수를 구하시오. (정수로 출력)

  • 데이터 : data_6_1_2.csv

③ 주어진 데이터를 이용하여 연도별 총 범죄 건수의 월평균 값을 구하고, 그 값이 가장 큰 연도의 총 범죄 건수의 월평균 값을 집계하시오. (반올림하여 정수로 출력)

  • 데이터 : data_6_1_3.csv
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
print("\n구급대별 평균 이동시간:")
## 
## 구급대별 평균 이동시간:
print(group_mean)
## 구급대
## 구급대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
print(f"\n이동시간 중 최대값: {max_time}")
## 
## 이동시간 중 최대값: 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
print(f"\n최대 학생/교수 비율 대학 : {univ}")
## 
## 최대 학생/교수 비율 대학 : 대학교46
print(f"\n최대 학생/교수 비율 대학의 교수 수 : {result}")
## 
## 최대 학생/교수 비율 대학의 교수 수 : 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("연도별 평균 총 범죄 건수:")
## 연도별 평균 총 범죄 건수:
print(group_mean)
## 연도
## 2018    527.333333
## 2019    520.500000
## 2020    514.916667
## 2021    528.333333
## 2022    524.416667
## Name: 총범죄건수, dtype: float64
print(f"\n최대 평균 총 범죄 건수: {result}")
## 
## 최대 평균 총 범죄 건수: 528

제 2 유형


아래는 학생들의 생활패턴과 신체, 거주지역 등에 대한 데이터이다.

  • 데이터
  1. data_6_2_train.csv (530명 데이터, 학생 구분 있음)
일평균수면시간 일평균학습시간 일평균스마트폰사용시간 몸무게 체격 기초대사량 거주지역 구분
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. data_6_2_test.csv (230명 데이터, 학생 구분 없음)
일평균수면시간 일평균학습시간 일평균스마트폰사용시간 몸무게 체격 기초대사량 거주지역
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]
print(test_df)
##      일평균수면시간  일평균학습시간  일평균스마트폰사용시간      키     몸무게  체격   기초대사량 거주지역
## 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]
# 학습용 데이터 – 데이터 타입 확인
train_df.info()
## <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
# 기초 통계 정보 확인 (문자열 열)
print("기초 통계 정보:")
## 기초 통계 정보:
print(train_df.describe(include='object'))
##            키   체격 거주지역    구분
## count    530  530  530   530
## unique     2    4    4     5
## top     Tall   XS   남구  유치원생
## freq     277  253  145   140
# 결측치 확인
print("\n결측치 개수:")
## 
## 결측치 개수:
print(train_df.isnull().sum())
## 일평균수면시간        0
## 일평균학습시간        0
## 일평균스마트폰사용시간    0
## 키              0
## 몸무게            0
## 체격             0
## 기초대사량          0
## 거주지역           0
## 구분             0
## dtype: int64
# 타겟 값 분포 확인
print("\n타겟 값 분포:")
## 
## 타겟 값 분포:
print(train_df['구분'].value_counts())
## 구분
## 유치원생    140
## 초등학생    121
## 고등학생    120
## 대학생      78
## 중학생      71
## Name: count, dtype: int64
# 데이터 타입 확인
print("테스트 데이터 타입 정보:")
## 테스트 데이터 타입 정보:
test_df.info()
## <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
# 기초 통계 정보 확인
print("\n기초 통계 정보 (문자열 열):")
## 
## 기초 통계 정보 (문자열 열):
print(test_df.describe(include='object'))
##             키   체격 거주지역
## count     230  230  230
## unique      2    4    4
## top     Short   XS   북구
## freq      126  126   74
# 결측치 확인
print("\n결측치 개수:")
## 
## 결측치 개수:
print(test_df.isnull().sum())
## 일평균수면시간        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.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
# 학습 정확도 출력
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
print(f"검증 데이터 정확도: {validation_acc:.4f}")
## 검증 데이터 정확도: 0.9245
# 테스트 데이터 예측
print("테스트 데이터 예측 시작...")
## 테스트 데이터 예측 시작...
prediction_test = rfc.predict(test_df)

# 예측 결과를 데이터프레임으로 변환
result = pd.DataFrame({'pred': prediction_test})

# 예측 결과 출력
print("예측 결과:")
## 예측 결과:
print(result.head())  # 상위 5개 결과 출력
##    pred
## 0  고등학생
## 1  초등학생
## 2   중학생
## 3  유치원생
## 4  고등학생
# 결과 CSV 저장
result.to_csv('result.csv', index=False)
print("예측 결과가 'result.csv'에 저장되었습니다.")
## 예측 결과가 'result.csv'에 저장되었습니다.

제 3 유형


  1. 주어진 데이터를 이용하여 항암제를 투여받은 환자들의 부작용 분포와 감기약을 투여받은 환자들의 부작용 분포 간 차이가 있는지 확인하시오.

    데이터

    1. 항암제 투여 환자들의 관찰된 부작용
      [무증상, 속쓰림, 무증상, 무증상, 무증상, 조금아픔, 무증상, 조금아픔, 무증상, 조금아픔, 무증상, 아픔, 무증상, 조금아픔, 무증상, 아픔, 무증상, 속쓰림, 무증상, 아픔, 무증상]

    2. 감기약 투여 환자들의 부작용 발생 비율

    • 아픔 5% / 조금아픔 10% / 속쓰림 15% / 무증상 70%
  • 귀무가설(\(H_0\)) : 감기약의 부작용과 항암제의 부작용은 동일하다.

  • 대립가설(\(H_1\)) : 감기약의 부작용과 항암제의 부작용은 다르다.

    항암제 투여 환자들 중 ‘무증상’ 비율을 0과 1 사이로 구하시오.

    감기약의 부작용 비율과 항암제의 부작용 관찰 값이 통계적으로 유의미하게 차이가 있는지 카이제곱 검정을 이용하여 검정 통계를 구하시오.

    위의 p-value를 구하시오.


  1. 주어진 데이터를 이용하여 다중선형회귀 문제를 해결하시오.

    데이터 : 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
# 전체 비율 출력
print("\n각 카테고리 비율:")
## 
## 각 카테고리 비율:
print(df['항암제'].value_counts(normalize=True))
## 항암제
## 무증상     0.55
## 조금아픔    0.20
## 아픔      0.15
## 속쓰림     0.10
## Name: proportion, dtype: float64
# 전체 개수 출력
print("\n각 카테고리 개수:")
## 
## 각 카테고리 개수:
print(df['항암제'].value_counts())
## 항암제
## 무증상     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
print(f"p-value: {pvalue:.3f}")
## p-value: 0.073
if pvalue < 0.05:
    print("결론: 기대분포와와의 차이가 있습니다.")
else:
    print("결론: 기대 분포와의 차이는 유의미하지 않습니다.")
## 결론: 기대 분포와의 차이는 유의미하지 않습니다.
  • 카이제곱 검정(적합도 검정) 귀무가설(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
print("\np-value (Wind):", model.pvalues['Wind'],"\n")
## 
## p-value (Wind): 0.16909868598497724
print(model.summary())
##                             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예측 요약 결과:")
## 
## 예측 요약 결과:
print(summary)
##         mean   mean_se  ...  obs_ci_lower  obs_ci_upper
## 0  78.826312  0.864464  ...     65.171661     92.480964
## 
## [1 rows x 6 columns]
  • 유의미한 변수:

    • Ozone은 온도에 유의미한 영향을 미치는 유일한 변수로 확인되었습니다.

    • 반면, SolarWind는 통계적으로 유의미하지 않았습니다.

  • 모델 적합성:

    • R-squared 값은 0.500으로, 온도의 변동성 중 약 절반을 설명합니다.

    • 잔차가 정규성을 따르지 않을 가능성 및 다중 공선성 문제를 개선할 필요가 있습니다.

  • 실제 활용:

    • 새로운 데이터에서 예측된 온도는 78.83이며, 예측 정확도를 높이기 위해 추가 변수 또는 모델 수정이 필요할 수 있습니다.