4 minute read

간단한 데이터 정제 및 전처리

넘파이와 판다스 라이브러리를 불러오고, ufo 데이터셋을 불러온다.

처음 다운로드 된 데이터셋은 빈 칸에 null 값이 설정되어 있지 않다.

따라서 파일을 직접 수정하여 빈 칸을 null 값으로 대체하였다.

import numpy as np
import pandas as pd

ufos = pd.read_csv("C:/Users/dst78/OneDrive/바탕 화면/개인/ufos.csv")
ufos.head()
datetime city state country shape duration (seconds) duration (hours/min) comments date posted latitude longitude
0 10/10/1949 20:30 san marcos tx us cylinder 2700.0 45 minutes This event took place in early fall around 194... 4/27/04 29.883056 -97.941111
1 10/10/1949 21:00 lackland afb tx NaN light 7200.0 1-2 hrs 1949 Lackland AFB&#44 TX. Lights racing acros... 12/16/05 29.384210 -98.581082
2 10/10/1955 17:00 chester (uk/england) NaN gb circle 20.0 20 seconds Green/Orange circular disc over Chester&#44 En... 1/21/08 53.200000 -2.916667
3 10/10/1956 21:00 edna tx us circle 20.0 1/2 hour My older brother and twin sister were leaving ... 1/17/04 28.978333 -96.645833
4 10/10/1960 20:00 kaneohe hi us light 900.0 15 minutes AS a Marine 1st Lt. flying an FJ4B fighter/att... 1/22/04 21.418056 -157.803611

데이터셋에서 가독성이 좋지 않은 특성들을 가독성이 좋게 변환하고, 주요 특성들만을 추출하여 데이터셋을 만든다.

ufos = pd.DataFrame({'Seconds': ufos['duration (seconds)'], 'Country': ufos['country'],'Latitude': ufos['latitude'],'Longitude': ufos['longitude']})

ufos.Country.unique()
array(['us', nan, 'gb', 'ca', 'au', 'de'], dtype=object)

또한 데이터셋의 크기를 줄이기 위해 ‘Second’ 특성의 1초 ~ 60초 사이의 값을 가지는 특성들만을 추출

ufos.dropna(inplace=True)

ufos = ufos[(ufos['Seconds'] >= 1) & (ufos['Seconds'] <= 60)]

ufos.info()
<class 'pandas.core.frame.DataFrame'>
Index: 25863 entries, 2 to 80330
Data columns (total 4 columns):
 #   Column     Non-Null Count  Dtype  
---  ------     --------------  -----  
 0   Seconds    25863 non-null  float64
 1   Country    25863 non-null  object 
 2   Latitude   25863 non-null  float64
 3   Longitude  25863 non-null  float64
dtypes: float64(3), object(1)
memory usage: 1010.3+ KB

Country 특성은 범주형 특성이기 때문에 LabelEncoder를 이용하여 국가 코드로 변환

from sklearn.preprocessing import LabelEncoder

ufos['Country'] = LabelEncoder().fit_transform(ufos['Country'])

ufos.head()
Seconds Country Latitude Longitude
2 20.0 3 53.200000 -2.916667
3 20.0 4 28.978333 -96.645833
14 30.0 4 35.823889 -80.253611
23 60.0 4 45.582778 -122.352222
24 3.0 3 51.783333 -0.783333

모델 훈련

이제 모델 훈련을 하기 위해 데이터셋을 훈련셋과 테스트셋으로 나눈다.

데이터셋의 레이블은 Country이다.

from sklearn.model_selection import train_test_split

selected_features = ["Seconds", "Latitude", "Longitude"]

X = ufos[selected_features]
y = ufos["Country"]

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

모델 훈련은 로지스틱 회귀 모델을 이용하여 훈련한다.

from sklearn.metrics import accuracy_score, classification_report
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
model.fit(X_train, y_train)
predictions = model.predict(X_test)

print(classification_report(y_test, predictions))
print('Predicted labels: ', predictions)
print('Accuracy: ', accuracy_score(y_test, predictions))
              precision    recall  f1-score   support

           0       1.00      1.00      1.00        41
           1       0.81      0.21      0.33       250
           2       1.00      1.00      1.00         8
           3       1.00      1.00      1.00       131
           4       0.96      1.00      0.98      4743

    accuracy                           0.96      5173
   macro avg       0.95      0.84      0.86      5173
weighted avg       0.95      0.96      0.95      5173

Predicted labels:  [4 4 4 ... 3 4 4]
Accuracy:  0.959404600811908
c:\Users\dst78\AppData\Local\Programs\Python\Python310\lib\site-packages\sklearn\linear_model\_logistic.py:458: ConvergenceWarning: lbfgs failed to converge (status=1):
STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.

Increase the number of iterations (max_iter) or scale the data as shown in:
    https://scikit-learn.org/stable/modules/preprocessing.html
Please also refer to the documentation for alternative solver options:
    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression
  n_iter_i = _check_optimize_result(

정확도가 대략 96%에 육박하는 결과를 얻는다.

해당 데이터셋의 훈련으로 웹 앱을 구현할 것이다.

Pickle

훈련된 모델을 pickle을 이용하여 second, 위도, 경도 갑이 포함된 데이터셋(X)을 대상으로 테스트한다.

import pickle
model_filename = 'ufo-model.pkl'
pickle.dump(model, open(model_filename,'wb'))

model = pickle.load(open('ufo-model.pkl','rb'))
print(model.predict([[50,44,-12]]))
[1]
c:\Users\dst78\AppData\Local\Programs\Python\Python310\lib\site-packages\sklearn\base.py:439: UserWarning: X does not have valid feature names, but LogisticRegression was fitted with feature names
  warnings.warn(

Flask

이제 훈련된 모델을 기반으로 웹을 작동하도록 하는 앱을 만든다.

가장 먼저 이전까지 작성한 코드들을 ipynb 파일로 다운로드 해야한다.

다운로드 후 실행환경에서 실행하면, ufo-model.pkl 파일도 같이 생성된다.

이제 기본적으로 다운로드 및 피클파일이 만들어 졌다.


웹을 만들기 위해 다음과 같이 web-app 폴더를 생성한다.

image.png ***

이제 web-app 폴더 안에 또 다른 여러 폴더들과 파일을 만들어 주어야한다.

static 폴더와 templates 폴더를 wep-app 바로 아래에 생성해준다.

또한, web-app 폴더 안에 app.py 파일과 requirements.txt 파일을 만들어준다.

app.py 파일은 웹을 실행하는데 필요한 코드를 삽입하고,

requirements.txt 파일 안에는 다운로드 받을 라이브러리를 적어준다.


app.py

해당 파일에서 밑줄 친 부분은 자신이 지정한 경로마다 다르다.

image.png ***


requirements.txt

image.png ***

이제 static 폴더 안에 css 폴더를 또 생성해 주고 그 css 폴더 안에 styles.css 파일을 만든다.

templates 폴더 안에는 index.html 파일을 만들어준다.

styles.css 파일은 만든 웹의 글꼴, 글자 크기 등의 스타일을 지정할 수 있고,

index.html 파일은 html언어로 웹을 만든다.


styles.css

image.png ***


index.html

필자는 가독성이 편하도록 보이는 텍스트 몇개를 한국어로 변환하였다.

image.png ***

폴더를 제외한 파일은 txt 파일로 먼저 작성 후 확장자를 변경해 주면 된다.

모든 폴더 및 파일을 작성했다면 터미널로 이동한다.

터미널로 이동한 다음 wep-app 폴더로 접근하기 위해 cd 명령어를 이용한다.

여기서 경로는 자신이 wep-app을 만든 경로마다 다르다.


cd C:\Users\dst78\Downloads\wep-app

아까 requirements.txt 파일에 작성되어 있는 라이브러리를 설치한다.


pip install -r requirements.txt

모든 설치가 끝나면 이제 웹을 작동할 모든 준비가 끝났다.

이제 터미널에 다음 명령어를 실행하여 웹을 실행해보자.


python app.py

위의 코드 실행 후 되지 않는다면 밑의 코드를 실행한다.


python3 app.py


성공한다면 다음과 같은 화면이 뜰 것이다.

image.png ***


서버 연결이 완료되었으므로 이제 사진의 밑줄 친 부분을 url 주소 검색창에 넣는다.

image.png

이상 없이 초, 위도, 경도를 넣으면 나라를 예측해준다.

만약 서버를 끊고 싶다면 터미널에서 ctrl + c 를 누르면 된다.