이 영역을 누르면 첫 페이지로 이동
포렌식 & 개발 이야기 - Forensics & Development 블로그의 첫 페이지로 이동

포렌식 & 개발 이야기 - Forensics & Development

페이지 맨 위로 올라가기

포렌식 & 개발 이야기 - Forensics & Development

Pental - Forensics / iOS / Windows / Android / Kakaotalk / Telegram / Etc

[빅데이터분석기사] 실기 대비 2일차 - 기출문제 2회

  • 2025.11.03 15:17
  • Programming/빅데이터분석기사 실기
글 작성자: pental

본 글은 개인적으로 공부하려고 작성한 내용입니다.
만일 저작권 및 다른 이유로 인해 문제가 발생할 소지가 있다면
pental@kakao.com 으로 메일 또는 해당 게시물에 댓글을 달아주시면 처리하도록 하겠습니다. 

본 내용은 빅데이터분석기사-2차실기 / 장은진 교수님의 강의를 듣고 개인적으로 추가 공부가 필요한 내용에 대해서 정리한 글입니다. 

작업형 1유형 문제 1번

주어진 Dataset에서 'CRIM' 값이 가장 큰 10개의 지역을 구하고 10개의 지역의 'CRIM' 값을 그 중 가장 작은 값으로 대체한 후, 'AGE' 컬럼 값이 80이상인 행의 'CRIM' 평균을 구하시오 (단, 출력 결과는 정수형으로 한다.)
import pandas as pd
df = pd.read_csv("./bigdata_csvfile/boston_housing_data.csv")
df

데이터는 총 506개의 행, 14개의 열로 이루어져있다.

문제에서는 CRIM 값이 가장 큰 10개의 지역을 구하라고 했기에 sort_values 함수를 이용해서 내림차순 정렬을 진행했다. (내림차순의 경우 ascending = False 옵션을 통해 진행한다.)

df.sort_values("CRIM", ascending = False, inplace = True)

정렬 결과를 df 자체에 결과하기 위해서 inplace = True 옵션을 통해서 df에 바로 반영되도록 했다.

10개의 지역이 뽑혔기 때문에, 이 중 CRIM 값이 제일 작은것은 9번 인덱스에 있는 행일 것이다. 그에 따라 iloc[9]을 통해서 최소 CRIM을 따로 변수에 저장한다.

min_crim = df.iloc[9]['CRIM']

그리고 이 최소 CRIM 값을 가장 큰 10개의 지역에 모두 대체해야 하기 때문에 다음과 같이 iloc를 통해서 min_crim으로 대체했다. [:10, 0] 을 사용한 이유는 10개까지의 행에 대해서 0번 컬럼(CRIM)의 값을 min_crim 으로 대체한다는 것이다.

df.iloc[:10, 0] = min_crim
result = df.loc[df['AGE'] >= 80, 'CRIM'].mean()
print(int(result))

답 : 5


작업형 1유형 문제 2번

주어진 Dataset에서 첫번째 행 부터 순서대로 80% 까지의 데이터를 추출 후'total_bedrooms' 컬럼의 중앙값으로 해당 컬럼의 중앙값으로 행당 컬럼의 결측치를 대체하고 'total_bedrooms' 컬럼의 대치 전후의 표준편차 차이를 구하시오
df = pd.read_csv("./bigdata_csvfile/california_housing.csv")
df.head()

먼저 데이터를 불러오고 어떻게 생겼는지 확인한다. 일단 80%의 데이터를 추출해야하기 때문에 전체 행의 갯수에서 0.8을 통해서 자를 위치를 구했다.

len(df) * 0.8 # 16512.0
df = df.iloc[:16512, :]

df.iloc를 통해서 전체 열에 대해서 16512행까지의 결과를 df에 저장한다.

std1 = df['total_bedrooms'].std()
median = df['total_bedrooms'].median()

그리고나서 표준편차와 중앙값을 구하기 위해서 .std(), .median() 을 사용했다.

df['total_bedrooms'] = df['total_bedrooms'].fillna(median)

구한 median 값을 결측값에 대치하기 위해서 .fillna()를 통해서 결측값을 중앙값으로 모두 넣어주었다. 그리고 결측값을 처리 후 표준편차를 비교하기 위해서 동일하게 .std()를 사용해서 표준편차를 계산한다.

std2 = df['total_bedrooms'].std()

위에서 구해놓은 std1과 std2의 차를 계산한다.

print(std1 - std2)

답 : 1.975147291645726


작업형 1유형 문제 3번

주어진 데이터의 population 컬럼의 평균으로부터 1.5x표준편차를 벗어나는 영역을 이상치라 판단하고 이상치들의 합을 구하시오. (단, 출력 결과는 정수형태로 하고 이상치는 '평균 - 1.5x표준편차 미만' 또는 '평균 + 1.5x표준편차 초과' 로 연산한다.)

데이터를 먼저 확인한다.

df = pd.read_csv("./bigdata_csvfile/california_housing.csv")
df.head()
std = df['population'].std()
mean = df['population'].mean()
print(std, mean) # np.float64(1132.462121765341), np.float64(1425.4767441860465)

표준편차를 계산하기 위해서 df[’population’].std()를 통해서 표준편차를 계산했고, 평균을 구하기 위해서는 .mean() 함수를 사용했다.

lower = mean - 1.5 * std
upper = mean + 1.5 * std

print(lower, upper) # -273.2164384619648 3124.169926834058

원래는 비슷한 유형으로 IQR 이상치 계산이 나오는걸로 기억하는데, 이 문제는 특이하게도 평균 - 1.5*표준편차 식으로 계산하라고 되어 있다. 따라서 lower와 upper 변수를 생성하여 이상치의 범위를 미리 계산해두었다.

cond1 = df['population'] < lower
cond2 = df['population'] > upper

계산 해둔 결과르 바탕으로 조건식을 세운다. 평균 +- 1.5 * 표준편차의 조건을 총 2개를 세웠다.

print(int(df[cond1 | cond2]['population'].sum())) # 5607295

위와 같이 `OR` 연산일 경우는 `|` 를 쓴다. 

다른 방법으로 조건 계산하는 식이 있지만 나는 별로 좋아하는 방법은 아니다.

# 다른 방법 조건 계산
result = df['population'].loc[(df['population'] > upper) | (df['population'] < lower)].sum()
print(int(result)) # 5607295

답만 잘 나오면 장땡 아닌교~

답 : 5607295


작업형 2유형

  • 주어진 E-Commerce_Shipping 데이터를 사용해서 고객이 주문한 물품의 제시간 도착여부(Reached.on.Time_Y.N)를 예측하는 분류 모델을 생성하여 결과를 제출하시오.
  • 단, 평가기준은 roc_auc_score이고, 제출 형태는 'cust_id' : id, 'reached_ontime' : value로 하며, 제출 파일 이름은 2nd_test_type2.csv로 한다.
  • 단, 학습데이터와 테스트 데이터는 각각 10000개, 999개로 나눈다.
df = pd.read_csv("./bigdata_csvfile/E-Commerce_Shipping.csv")
display(df.head())

이제 데이터를 읽어오는건 너무나 당연하게 쉬워진것 같다. 근데 구분자가 | ,- ,# 등으로 나오면 데이터 읽는 것부터 난이도 떡상~

print(df.info())

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10999 entries, 0 to 10998
Data columns (total 12 columns):
 #   Column               Non-Null Count  Dtype 
---  ------               --------------  ----- 
 0   ID                   10999 non-null  int64 
 1   Warehouse_block      10999 non-null  object
 2   Mode_of_Shipment     10999 non-null  object
 3   Customer_care_calls  10999 non-null  int64 
 4   Customer_rating      10999 non-null  int64 
 5   Cost_of_the_Product  10999 non-null  int64 
 6   Prior_purchases      10999 non-null  int64 
 7   Product_importance   10999 non-null  object
 8   Gender               10999 non-null  object
 9   Discount_offered     10999 non-null  int64 
 10  Weight_in_gms        10999 non-null  int64 
 11  Reached.on.Time_Y.N  10999 non-null  int64 
dtypes: int64(8), object(4)
memory usage: 1.0+ MB

먼저 10999개로 모두 동일 한것을 확인해보니 결측값은 없는것으로 확인된다. 단 4개의 컬럼에서 Dtype에 object로 되어 있는 것으로 보아 날리던지 One-Hot-Encoding을 하던지 고민해야하는 부분이다.

df.isnull().sum()

ID                     0
Warehouse_block        0
Mode_of_Shipment       0
Customer_care_calls    0
Customer_rating        0
Cost_of_the_Product    0
Prior_purchases        0
Product_importance     0
Gender                 0
Discount_offered       0
Weight_in_gms          0
Reached.on.Time_Y.N    0
dtype: int64

혹시라도 결측값이 있는지에 대해서 확인해보려고 `df.isnull().sum()`을 사용했으며 위 결과와 같이 결측값은 존재하지 않는다.

문제에서 분류라고 딱 줬는데, 이렇게 주는 경우는 드물다고 한다. 평가 지표를 바탕으로 분류인지 회귀인지 구별할 수 있다고 한다.

RMSE, MSE, F2 → 회귀 문제, ROC, ACC → 분류 문제

 

df['Reached.on.Time_Y.N'].value_counts()

Reached.on.Time_Y.N
1    6563
0    4436
Name: count, dtype: int64

일단 분류를 총 몇가지로 해야하는지 확인하기 위해서 `.value_counts()`를 사용하였다.

분류로 도출해야하는 종류는 0 또는 1로 딱 떨어지는 분류문제이다.

일단 위에서 확인했던 `object` 타입에 대해서는 라벨 인코딩을 진행해야한다. 그 이유는 다음과 같다.

columns = ['Warehouse_block', 'Mode_of_Shipment', 'Product_importance', 'Gender']
for col in columns :
    print(df[col].value_counts())
    
Warehouse_block
F    3666
D    1834
A    1833
B    1833
C    1833
Name: count, dtype: int64
Mode_of_Shipment
Ship      7462
Flight    1777
Road      1760
Name: count, dtype: int64
Product_importance
low       5297
medium    4754
high       948
Name: count, dtype: int64
Gender
F    5545
M    5454
Name: count, dtype: int64

각각 단순히 2 ~ 5개 정도의 값만 반복되기 때문에 라벨인코딩을 진행하면 좋을것 같다고 판단해서 라벨인코딩을 진행한다.

from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()

columns = ['Warehouse_block', 'Mode_of_Shipment', 'Product_importance', 'Gender']

for col in columns :
    le.fit(df[col])
    df[col] = le.transform(df[col])

print(df.info())

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10999 entries, 0 to 10998
Data columns (total 12 columns):
 #   Column               Non-Null Count  Dtype
---  ------               --------------  -----
 0   ID                   10999 non-null  int64
 1   Warehouse_block      10999 non-null  int64
 2   Mode_of_Shipment     10999 non-null  int64
 3   Customer_care_calls  10999 non-null  int64
 4   Customer_rating      10999 non-null  int64
 5   Cost_of_the_Product  10999 non-null  int64
 6   Prior_purchases      10999 non-null  int64
 7   Product_importance   10999 non-null  int64
 8   Gender               10999 non-null  int64
 9   Discount_offered     10999 non-null  int64
 10  Weight_in_gms        10999 non-null  int64
 11  Reached.on.Time_Y.N  10999 non-null  int64
dtypes: int64(12)
memory usage: 1.0 MB

`pd.get_dummies()`와 뭐가 다른지도 확인이 필요하다. (TODO)

일단 전처리가 완료 되었으면, 문제 지문과 같이 `train`과 `test` 데이터를 각각 10000, 999개로 나눈다.

train = df.iloc[0:10000]
test = df.iloc[10000:10999]

from sklearn.model_selection import train_test_split
X = train.drop(columns = ['ID', 'Reached.on.Time_Y.N'])
y = train['Reached.on.Time_Y.N']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 123)

또한 `train_test_split`을 통해서 `X_train`, `X_test`, `y_train`, `y_test`를 각각 나누어 주었다. 

X의 경우는 독립변수로써, 우리가 구해야하는 `Reached.on.Time_Y.N`을 뺀 모든 컬럼이다. (ID는 학습에 도움이 되지 않으니 뺐다.)

y의 경우는 종속변수로써, 우리가 구해야하는 `Reached.on.Time_Y.N`만 가지고 있는다.

from sklearn.ensemble import RandomForestClassifier

rfc = RandomForestClassifier(n_estimators = 170, max_depth = 30, random_state = 123)
rfc.fit(X_train, y_train)
pred = rfc.predict(X_test)

from sklearn.metrics import roc_auc_score, accuracy_score
roc = roc_auc_score(y_test, pred)
acc = accuracy_score(y_test, pred)
print(roc)
print(acc)

당연하게 `RandomForest`를 사용한다. (근데 오탈자 주의해야한다. 가끔씩 오탈자가 발생하는것 같다.) 이문제는 분류 문제이기 때문에 `RandomForestClassifier`을 사용했다. 

또한 문제에서는 성능평가 지표로 `roc_auc_score`를 사용하라 했기에 `roc_auc_score`도 출력하고 정확도도 궁금하기 때문에 `accuracy_score`도 `import`해서 출력해봤다.

근데 지금 `n_estimators`가 170, `max_depth`가 30으로 줬을때 `roc`와 `acc`의 값는 각각 0.680, 0.681이다.

from sklearn.ensemble import RandomForestClassifier

rfc = RandomForestClassifier(random_state = 123)
rfc.fit(X_train, y_train)
pred = rfc.predict(X_test)

from sklearn.metrics import roc_auc_score, accuracy_score
roc = roc_auc_score(y_test, pred)
acc = accuracy_score(y_test, pred)
print(roc)
print(acc)

랜덤포레스트에 `하이퍼파라미터` 튜닝을 하지 않고 그냥 돌렸을때의 `roc`와 `acc`의 값은 0.684, 0.683이다. (이러면 하이퍼파라미터 튜닝을 하지 않는게 더 좋은거 아닌가?)

여기서 마치는게 아니라 이게 테스트 데이터에 대해서도 예측을 진행하고 저장까지 해야한다.

test_data_X = test.drop(columns = ['ID', 'Reached.on.Time_Y.N'])
test_data_y = test['Reached.on.Time_Y.N']
pred2 = rfc.predict(test_data_X)

따라서 test데이터에서 위에서 진행했던 train_test_split 전 종속, 독립 변수를 나눈것처럼 test에서도 동일하게 ID와 Reach.on.Time_Y.N을 날려준다. 그리고 기존에 생성해준 모델을 이용해서 test_data_X를 예측한다. 이때 예측에 사용되는 독립변수는 ID, Reach.on.Time.Y_N을 제외한 모든 데이터이다.

result = pd.DataFrame(
    {
        'ID' : test['ID'],
        'reached_ontime' : pred2
    }
)
result.to_csv("2nd_test_type2.csv", index = False)
print(pd.read_csv('2nd_test_type2.csv').head())

      ID  reached_ontime
0  10001               1
1  10002               0
2  10003               0
3  10004               1
4  10005               0

결과를 저장할때, ID도 포함해서 CSV를 생성하라 했기 때문에 `test[’ID’]`를 그대로 가져와서 사용했다. 다른 문제에서도 몇번 보이던 패턴이었고, 대체적으로 `pred` 열로 생성하라 하는데 이 문제는 특이하게도 `reached_ontime`의 이름으로 열을 생성하라 했다. 

또한 `result.csv` 가 아닌 `2nd_test_type2.csv`로 저장하는것도 조금 특이한 부분이라 생각된다.

즉, 문제를 제대로 확인해야 한다는 생각이 든다.

 

추가 공부해야하는 것

1. 이 문제를 풀면서 생각된 것은 원핫인코딩과 라벨인코딩이 뭐가 다른것인지?
2. sklearn.preprocessing.LabelEncoder과 pandas.get_dummies가 무엇이 다른지?
3. 문제를 제대로 읽고 회귀인지 분류인지 파악하기
4. RMSE, MSE, F1, ACC, ROC 를 통해서 회귀인지 분류인지 파악할수 있다.
5. 만약 그래도 모르겠다 싶으면 종속변수를 .value_counts를 통해서 1~4개 등으로 나타나는지 아니면 각각 다 다른값인지를 확인하면 회귀인지 분류인지 확인 할 수 있다.
6. 학습데이터로 예측만하고 그 데이터를 그대로 제출하지 말고 test 데이터에 대해서 예측하고 결과 저장하고 확인까지 하기

저작자표시 비영리 (새창열림)

'Programming > 빅데이터분석기사 실기' 카테고리의 다른 글

[빅데이터분석기사] 실기 대비 1일차 - 모의고사  (0) 2025.11.03

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [빅데이터분석기사] 실기 대비 1일차 - 모의고사

    [빅데이터분석기사] 실기 대비 1일차 - 모의고사

    2025.11.03
다른 글 더 둘러보기

정보

포렌식 & 개발 이야기 - Forensics & Development 블로그의 첫 페이지로 이동

포렌식 & 개발 이야기 - Forensics & Development

  • 포렌식 & 개발 이야기 - Forensics & Development의 첫 페이지로 이동

검색

메뉴

  • 홈
  • 태그
  • 미디어로그
  • 위치로그
  • 방명록

카테고리

  • Category (517) N
    • Forensics (106)
      • Magnet AXIOM (28)
      • Digital Forensics Informati.. (9)
      • Iphone Forensics (25)
      • DFC (7)
      • 디지털포렌식전문가2급 자격증 (10)
      • FTK ACE 자격증 (7)
    • 이것저것 (23)
      • Ubuntu (6)
      • 디스코드 봇 (4)
      • Volatility GUI (2)
    • CTF (32)
      • NEWSECU (14)
      • CTF-d (5)
      • Puzzel - Network Forensics (2)
      • Security Traps (2)
      • system32.kr (5)
      • HMCTF (4)
    • Programming (319) N
      • C (10)
      • Python (11)
      • 백준 (263)
      • 프로그래머스 (32)
      • 빅데이터분석기사 실기 (2) N
    • 그냥 개발 및 잡담 (17)
      • Docker (2)
      • Google Cloud (3)
      • OS 개발 (3)
    • Best of Best (20)

최근 글

인기 글

댓글

공지사항

아카이브

태그

  • 파이썬
  • axiom
  • Forensics
  • pental
  • 프로그래머스
  • 포렌식
  • 백준
  • 디지털포렌식
  • 전체 보기…

정보

pental의 포렌식 & 개발 이야기 - Forensics & Development

포렌식 & 개발 이야기 - Forensics & Development

pental

블로그 구독하기

  • 구독하기
  • RSS 피드

방문자

  • 전체 방문자
  • 오늘
  • 어제

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. Copyright © pental.

티스토리툴바