로운's 기술노트

Chapter 3. 데이터 분석 입문 (10주차_3/5) 본문

내배캠_데이터분석가_'24.04~08/회고

Chapter 3. 데이터 분석 입문 (10주차_3/5)

로운's 2024. 6. 20. 00:43
심화프로젝트 3일 차

 

어제 하던 단어 토큰화와 정규화를 보완하고 TF-IDF를 적용해 보았다.

정규화 참 오랜만에 써보는 듯하다

 

그러나 막상 적용해 보니 인코딩이 깨지는 부분이 발생하였다.

여러 방법을 찾아보다가 utf-8로 정착하였다. (처음엔 오류 나던 녀석이...)

# df = pd.read_csv(file_address, encoding="latin1")  # 기존_text일부 깨짐
# df = pd.read_csv(file_address, encoding="iso-8859-1")  # text일부 깨짐
# df = pd.read_csv(file_address, encoding="utf-16")  # 에러 UnicodeError: UTF-16 stream does not start with BOM
# df = pd.read_csv(file_address, encoding="cp1252")  # 에러 UnicodeDecodeError: 'charmap' codec can't decode byte 0x90 in position 1146: character maps to <undefined>
# df = pd.read_csv(file_address, encoding="utf-8-sig")  # 한글오류
df = pd.read_csv(file_address, encoding="utf-8")  # 한글오류


# utf-8과 utf-8-sig의 차이는 Byte Order Mark(BOM) 유무! (BOM: 인코딩 방식을 알려주는 메타데이터)
# BOM은 가시적인 데이터가 아니기 때문에 아래 코드로 식별이 가능!
from google.colab import drive
drive.mount('/content/drive')

file_path = '/content/drive/MyDrive/Data_Python/sp/df (1).csv'

with open(file_path, 'rb') as file:
    first_bytes = file.read(3)
    if first_bytes == b'\xef\xbb\xbf':
        print("이 파일에는 UTF-8 BOM이 포함되어 있습니다.")
    else:
        print("이 파일에는 UTF-8 BOM이 포함되어 있지 않습니다.")
# Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).
# 이 파일에는 UTF-8 BOM이 포함되어 있지 않습니다.  >> 최종 utf-8 채택!!

 

사실 utf-8도 한글이 이상하게 표현되긴 하지만 이건 원본 데이터자체가 문제가 있었던 것으로 확인!

해석이 불가능한 한글과 한자, 링크, 불용어 등 제거가 시급하다-

# 출력물
41       Militante y obrero de los Sue堅os Revolucionari...
42       Love Animals? FetchFind is the new way to find...
43                 Baby I'm perfect for you @NiallOfficial
44       Kennedy J Abulala ni mwalimu anayeienzi kazi y...
45            [ Krothedj@gmail.com ] [ Instagram - DJKRO ]
46           Slightly ginger with blue eyes.\nPark Run 돑_뺵
47           Just Living Life at the top of the food chain
48                                      19 | NSS | IPGKK 됍

 

이것저것 고민하다 보니 정규화가 점점 늘어나 결국엔 10종이 되어버렸다..

 

그리고 빠른 처리 속도와 메모리 효율 때문에 어제 적용했던 spacy 라이브러리는 

안타깝게도 불용어 패키지가 없어 부득이 nltk (Natural Language Toolkit)로 급선회하였다.

# 단어 토큰화(Word Tokenization) & 정규화 처리
import re
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from nltk.stem import PorterStemmer

# NLTK의 불용어 리스트 다운로드
nltk.download('stopwords')
nltk.download('punkt')

# 불용어 리스트 가져오기
stop_words = set(stopwords.words('english'))

# 어간 추출기 초기화
stemmer = PorterStemmer()

def preprocess_text(text):
    if isinstance(text, str):  # 문자열인 경우에만 처리
        # HTML 태그 필터링
        text = re.sub(r'<.*?>', '', text)

        # 소문자 변환
        text = text.lower()

        # 숫자 필터링
        text = re.sub(r'\d+', '', text)

        # 특수 문자 및 구두점 필터링
        text = re.sub(r'[^\w\s]', '', text)

        # ASCII 문자 범위 이외의 모든 문자 필터링
        text = re.sub(r'[^\x00-\x7F]+', '', text)

        # "@"로 시작하는 단어 필터링 (멘션)
        text = re.sub(r'@\w+', '', text)

        # 한글 필터링
        text = re.sub(r'[ㄱ-ㅎㅏ-ㅣ가-힣]', '', text)

        # URL 필터링
        text = re.sub(r'http\S+', '', text)
        text = re.sub(r'www\.\S+', '', text)

        # 단어 토큰화
        tokens = word_tokenize(text)

        # 불용어 필터링와 어간 추출
        tokens = [stemmer.stem(token) for token in tokens if token.lower() not in stop_words]

        # 최종 텍스트 반환
        return ' '.join(tokens)

    else:
        return ''  # 문자열이 아닌 경우 빈 문자열 반환

# 전처리 적용
df['description2'] = df['description'].apply(preprocess_text)
print(df[['description', 'description2']])

>> 출력예시
20046  whatev like problem chargern foreverroy edm mu...  
20047  teambarcelona look lost follow follow heart br...  
20048  antistatist homeschool kid aspir thoughtlead f...

 

결국, 아름다운 토큰화가 완료되었다-

다시 힘을 내어 TF-IDF를 적용했으나 27,860차원이라는 어마무시한 녀석이 탄생하게 되었다.

 

from sklearn.feature_extraction.text import TfidfVectorizer

# TF-IDF 벡터화 객체 초기화
tfidf_vectorizer = TfidfVectorizer()

# TF-IDF 적용할 데이터 준비 (전처리된 텍스트를 사용)
cleaned_texts = df['description'].apply(preprocess_text)

# TF-IDF 벡터화 및 변환
tfidf_matrix = tfidf_vectorizer.fit_transform(cleaned_texts)

# TF-IDF 결과를 데이터프레임으로 변환하여 description3 컬럼에 저장
df['description3'] = list(tfidf_matrix.toarray())

# 데이터프레임 출력
print(df[['description', 'description3']])

> 출력예시
20046  [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...  
20047  [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...  
20048  [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...  


# 차원확인
len(list(df['description3'])[0])

> 출력
27860

 

이로써 전처리는 어느 정도 마무리가 되었고, 남은 NLP는 파트를 나누어 진행해보고자 한다.

프로젝트는 아래와 같이 크게 3파트로 나누어 정확성 비교를 목표로 하고 있다.

 

1. 다양한 모델의 앙상블로 정확성 극대화

2. NLP & 나이브베이즈 적용

3. NLP &  허깅페이스(Hugging Face)의 Sentence Embedding 적용

 

추후 시간이 된다면 '문장 토큰화'도 추후에 적용하여 비교해보고자 한다.

 

 

 

 

Comments