KT AIVLE/데이터 분석, ML, DL

[KT AIVLE DX 트랙 7기] 미니프로젝트 1차

Dori1998 2025. 4. 20. 17:55

KT 에이블스쿨 7기 DX 트랙에 기자단으로 신청하기도 하였고, 복습을 통한 역량을 강화, 습득을 목적으로 작성되었음을 알려드립니다.

 

그럼, 복습 Let's go

 


전체적인 프로젝트에서 가장 헷갈렸던 부분들만 집중적으로 코멘트를 남기고자 합니다.

제가 헷갈렸던 부분들이 「비전공자」에게 큰 힘이 되었으면 좋겠습니다 :)

 

1.

import seaborn as sns
import matplotlib.pyplot as plt
sns.countplot(x = 'Address1', data = df)
plt.show()

df.drop(df[df['Address1'] == '-'].index, inplace = True)

 

 일단 여기 부분에서 df.drop(df[df['Address1'] == '-'].index, inplace = True)에 대한 설명을 하고자 합니다.

 

df["address1"] == "-" 만 한다면, 단순히 "-"에 대한 address의 조건 value값들이 나오겠죠?

이를 df[]로 한번 더 감싸야 이들을 추출할 수 있어요!

 

df.drop()DataFrame.drop(labels=None, *, axis=0, index=None, columns=None, level=None, inplace=False, errors='raise')

로 되어있어요! 즉, labels 한개로 묶어야 한다는 것이죵.

 

① df["Address1"] == "-"  : "Address1" 컬럼에 있는 각 값이 "-"와 같은지를 비교해서 True / False 로 나타냄

 

예시:print(df["Address1"] == "-")
0    False
1     True
2    False
Name: Address1, dtype: bool

 

② df[df["Address1"] == "-"] : 위에서 True였던 행만 선택한다.

 

print(df[df["Address1"] == "-"])
   Name Address1
1   Bob        -

 

③ df[df["Address1"] == "-"].index : 방금 조건에 맞는 행의 인덱스(행 번호)만 뽑아낸다.

 

print(df[df["Address1"] == "-"].index)Int64Index([1], dtype='int64')

 

2.  Drop() 와 Dropna() 의 차이점

메서드 목적
drop() 특정 행 또는 열을 인덱스나 컬럼 이름으로 제거할 때 사용
dropna() 결측값(NAN)이 포함된 행 또는 열을 제거할 때 사용

 

3. Drop()

from sklearn.model_selection import train_test_split
x = df_preset.drop(columns = ['Time_Driving'])
y = df_preset['Time_Driving']
X_train, X_valid, y_train, y_valid = train_test_split(x, y, test_size = 0.2, random_state = 42)

 

내가 가장 헷갈렸던 부분은 x = df_preset.drop(columns = ['Time_Driving'])와  x = df_preset.drop(df["Time_Driving"])  의 차이였다.

여기에서 가장 놓쳤던 부분은 drop은 "columns", "index" 만 제거할 수 있다는 것, 즉 Series 를 추출하는 건 안 된다는 것이다.

 

x = df_preset.drop(columns=['Time_Driving'])

 

이건 "Time_Driving"을 제거하는 코드이다.

Columns = 를 명시해서, 어떤 컬럼을 제거하고, 삭제할지 지정하는 아주 정석적인 방법이라고 할 수 있다.

 

그럼 왜? x = df_preset.drop(df["Time_Driving"])는 안 되는걸까?

df["Time_Driving"]은 Series (즉, 열 값들의 리스트)이기 때문이다. 즉,

 

0    10
1    15
2    20
Name: Time_Driving, dtype: int64

 

이런 형태도 남아있는 것이다.

drop()은 행 인덱스나 열 이름을 삭제할 때 쓰는 거라서, 위처럼 Series 전체를 drop 대상 label로 넘기면 오류난다는 것이다.

다시 말해서 drop은 "이름(인덱스나 컬럼)을 삭제하는 함수"이지, "Series(값 목록)"을 넣으면 혼란스러워서 에러가 발생한다는 것

 

4. model = Sequential

model = Sequential()
model.add(Dense(64, activation='relu', input_shape=(87,)))
model.add(Dropout(0.2))
model.add(Dense(32, activation='relu'))
model.add(Dense(16, activation='relu'))
model.add(Dense(1))

model.compile(loss='mse', optimizer='adam', metrics=['mae', 'mse'])

es = EarlyStopping(monitor='val_loss', patience=5)

checkpoint_path = 'best_model.keras'  # 파일 경로를 수정
mc = ModelCheckpoint(checkpoint_path, monitor='val_loss', verbose=1, save_best_only=True)

history = model.fit(X_train, y_train, epochs=30, batch_size=16,
                   validation_data=(X_valid, y_valid),
                   callbacks=[es, mc]
                   )

 

먼저, Model = Sequential() → model.compile() → Earlystopping, Checkpoint_path → History로 이어져야 한다.

 

Model = Sequential()로 시작해서

model.add(Dense()) 로 시작하는데, 가장 헷갈렸던 부분은 "input_shape(87,) 이 부분!!

 

먼저 input_shape = (87,) 는 "이 모델이 처음 받을 데이터의 모양이 (87,)이라고 선언하는 것이고, 입력 베터의 길이가 87인 데이터를 받는다는 것으로 설명할 수 있다!

 

더 자세히 풀어보자

 

X_train.shape 을 했을 때

(1000, 87) 라고 나왔으면

- 1000개 샘플(행)

- 각 샘플은 87개의 특성(Feature)

로 이뤄져있다는 것을 알 수 있습니다. 즉, 한 행(row)의 길이가 87개라는 뜻이다.

 

다시 말하자면, 우리는 "input_shape"가 '딱 한 개의 샘플'을 기준으로 생각해야 한다는 것이다.

model.add(Dense(64, activation='relu', input_shape=(87,)))

→ 87개의 입력을 받아서
→ 64개의 출력을 만드는 Dense 레이어를 추가하는 것!!

 

형식 정리를 하자면

input_shape=(87,) 87차원 벡터 (1D 입력)
input_shape=(28, 28) 2D 이미지 (예: 흑백 이미지)
input_shape=(64, 64, 3) 컬러 이미지 (64x64 RGB)
input_shape=(10, 1) 시계열 데이터 (10타임스텝, 1특성)

 

인자 이름설명

X_train, y_train 학습용 데이터와 정답 라벨
epochs=30 학습을 총 30번 반복
batch_size=16 한 번에 16개씩 데이터를 나눠 학습
validation_data=(X_valid, y_valid) 검증용 데이터 (학습 중에 평가용으로 사용)
callbacks=[es, mc] 조기 종료(EarlyStopping)나 모델 저장(ModelCheckpoint) 등을 자동으로 수행하는 기능

 

이것으로 미니프로젝트를 마치겠습니다!!

감사합니다!