KT AIVLE School/[TIL] AIVLE School 당일 복습

[TIL] [KT AIVLE School] KT 에이블스쿨 6기(DX 트랙) 2주차 3일. 데이터 다루기 - 파일 읽고 쓰기 / 워드 클라우드 만들기 / 엑셀 파일 다루기 / 이메일 보내기

guoyee94 2024. 9. 11. 22:54

 

오늘은 데이터 다루기 마지막 날.

 

파이썬이 외부의 파일이나 프로그램과 어떤 식으로 상호작용하는지를 배웠다.

 

데이터분석 전반에서 많이 쓰이지는 않지만, 파이썬의 확장성을 체험해볼 수 있었다.

 

목차
- 파일 읽고 쓰기
- 워드클라우드 만들기
- 엑셀 파일 다루기
- 이메일 보내기

 

 

 


 

파일 읽고 쓰기

 

 

말 그대로 외부 파일을 읽고 쓰고 수정하는 법.

 

데이터분석 플로우에서는 pandas의 내장 함수 read_csvread_json 등을 많이 활용한다.

 

그것들의 전신이 되는 파이썬 내장 함수를 알아보자.

 

 

 

  • open('파일명.확장자', '모드')

주로 변수에 할당해서 f = open('MyFile.txt', 'w')와 같이 쓴다.

 

'모드'에 들어가는 게 뭐냐에 따라서 기능이 조금씩 다른데

w write 새로 만들기, 동명의 파일을 덮어쓴다.
r read 읽기, 지정한 명칭과 같은 파일이 없으면 에러가 난다.
a append 추가하기, 명칭이 없으면 새로 만들고 있으면 그거 읽어온다.
x exclusive 배타적 생성, write처럼 새로 만들지만 동명의 파일이 있으면 에러가 난다.

 

찾아보니 바이너리 모드(텍스트 이외 처리 ) b, 텍스트 모드 t 등도 있더라.

 

 

여튼 이렇게 만든 open 객체에서 파일을 지지고 볶는다.

 

# 파일 쓰기
f.write('안녕하세요?\n')

# 내용 읽기
f.read()              ## 내용을 반환한다.

# 파일 닫기
f.close()

# 파일 여러 줄 쓰기
hello = ['안녕하세요?\n', '만나서 반갑습니다!\n', '우리 사이좋게 잘 지내요.\n']
f.writelines(hello)

# 파일 한 번에 읽기    
f.readlines()          ## 꺼내 와서 각 행을 리스트에 담는다.

 

처음 보는 거지만 .readlines()는 유용하지 않을까 생각한다.

 

행을 리스트에 담아두는 거잖아.

 

전화번호부라든가, 시계열 데이터처럼

개행(\n)으로 item이 구별되는 자료에 유용하려나

 

 

 

  • pathlib.path

얜 파이썬 내장 함수가 아니라 외부 라이브러리다. from pathlib import path 형태로 쓴다.

from pathlib import Path

# 홈 디렉터리 확인
print(Path.home())

# 작업 디렉터리 확인
print(Path.cwd())       ## cwd = current work directory

# 디렉터리 내용 확인
files = Path.cwd().glob('*')        ## '*' : 모든 이름, 모든 확장자. '*.*'과 같은 의미
                                    ## ex) '*.txt' = txt 확장자인 모든 파일  
for f in files:
     print(f)
     
# 디렉터리 만들기
Path('Files').mkdir(exist_ok=True)  ## mkdir = make directory

 

 

 


 

워드 클라우드 만들기

 

워드 클라우드를 그리는 과정 자체는 강사님께서 미리 코드를 주셨다.

# 라이브러리 불러오기
import matplotlib.pyplot as plt
from wordcloud import WordCloud
%config InlineBackend.figure_format='retina'

# 워드 클라우드 만들기
wordcloud = WordCloud(font_path = 'C:/Windows/fonts/HMKMRHD.TTF',
                      width=2000,
                      height=1000,
                      background_color='white').generate_from_frequencies(wordCount)   ## 자료를 집어넣을 곳,
                                                                       ## 이걸 기반으로 워드클라우드 객체 생성

# 표시하기
plt.figure(figsize=(12, 6))
plt.imshow(wordcloud)
plt.axis("off")
plt.tight_layout(pad=0)
plt.show()

 

우리가 할 줄 알아야 하는 건 저게 아니라 워드클라우드 생성에 쓰일 딕셔너리!

 

위 코드의 wordCount가 그것이다.

 

가치있는 워드 클라우드를 위해 이 딕셔너리는 몇몇 조건을 만족시켜야 하는데

 

 

  • 우선 특수문자 문장부호, 화이트스페이스가 제거되어 있어야 한다.
# 파일 읽기
file = open('Dream.txt', 'r', encoding='UTF-8')   ## '-' 등 2byte 문자들을 처리하기 위한 인코딩
text = file.read()
file.close()

# 공백을 구분자로 하여 단어 단위로 자르기
wordList = text.split()   
## 반드시 매개변수 없이. 매개변수로 ' ' 넣으면 다른 다른 화이트스페이스는 없어지지 않는다.

 

.

  • 그리고 키(단어) : 값(등장수) 쌍으로 구성되어야 한다.
# 중복 단어 제거                      ## 키를 만들기 위해 중복 제거. 키는 겹치면 안되니까
worduniq = set(wordList)

# 딕셔너리 선언
wordCount = {}

# 단어별 개수 저장                    ## 중복 있는 거에서 구해야 함
for w in worduniq:
    wordCount[w] = wordList.count(w) ## 키 : wordCount[w], 밸류 : wordList.count(w)

 

 

 

  • 마지막으로 불필요한 단어(조사, 전치사, 대명사 등)가 제외되어야 한다.
# 제외 대상 조사
del_word = ['the','a','is','are', 'not','of','on','that','this','and','be','to',
            'from', 'in', 'as', 'with', 'by','an', 'There', 'but', 'for', 'there',
            'which', 'so', 'can', 'about', 'its', 'who', 'at', 'would', 'they',
            'have', 'even', 'out', 'when', 'what', 'he', 'she', 'some', 'we', 'you',
            'my', 'An', 'As', 'too', 'than','were', 'do', 'did', 'He', 'She',
            'still', 'may', 'It', 'it', 'has', 'might', 'The', 'will', 'into',
            'through', 'wothout', 'In', 'more', 'their', 'Their', 'was', 'or', 'For', 'our']

# 제외하기
for w in del_word:
    if w in wordCount:
        del wordCount[w]

 

노가다의 산물     지금 보니까 without이 wothout으로 되어 있다.

 

제외 대상은 일단 마구잡이로 불필요해 보이는 걸 찾아 썼다.

 

워드클라우드를 여러 번 그려 가며 하니 찾기 쉬웠다.

 

그 결과물

그래도 지우지 못한 것들이 보인다. 대문자나 복수형 등.

 

워드클라우드의 핵심은 키워드의 가시성이라고 생각한다.

 

내가 사용한 글은 BBCIT report에서 가져 온 특집기사 

An AI walks into a bar... Can artificial intelligence be genuinely funny?이었다.

 

나름 AI, comedy, jokes등 키워드가 잘 뽑힌 듯.

 

다만 comedian과 comedians가 나뉘거나, Comedy와 comedy가 따로 인식되거나,

write과 wrote이 따로 인식되는 등의 문제를 해결해야 할 듯하다.

 

사족

국어의 경우, 수많은 조사와 어미를 어떻게 처리해야 할까?
문법적 기능을 제하고 키워드로만 따져 보면
'먹다 = 먹는다 = 먹겠다 = 먹니 = 먹어서 = 먹고 = 먹지만'인데...

'어근부 + 형식부'의 구분?
그럼'울다 = 우는'이나  '걷다, 걷고 = 걸어서, 걸은'을 어떻게 처리하지?

어떻게 '높다 = 높다랗다 = 드높다 ≠ 높이다'를 구분시켜야 할까?

'철수는'에서 '는'을 삭제한다면, '맛있는'의 '는'을 어떻게 남길까?

관련 지식 체크해 두자.

 

 

 

 

 

 

 


 

엑셀 파일 다루기

 

 

엑셀 파일은 tabular 데이터라는 점에서 이후 데이터플로우와 유사할 것 같다.

 

엑셀 다루기는

import openpyxl로 시작한다.

 

파이썬에서 액셀을 다루게 해 주는 라이브러리.

 

별칭은 보통 xl 이다.

 

  • 읽기, 탐색하기
# 라이브러리 불러오기
import openpyxl as xl     # open python xlsx

# 워크북 오브젝트를 선언(엑셀 파일 열기)
wb = xl.load_workbook('Fruit.xlsx')     # df = pd.read_csv와 비슷하다.

# 시트 선택
sheet1 = wb['Sheet1']  # 엑셀의 가장 큰 단위인 시트 객체가 df 같은 역할을 한다.

# 데이터 영역 확인
print(sheet1.min_row, sheet1.max_row)        # 시작 행, 끝 행 확인
print(sheet1.min_column, sheet1.max_column)  # .shape()같은 효과

# 값을 불러오는 법
# 1. 셀 이름으로 확인 
sheet1['A1'].value        ### 딕셔너리와 다르게 .value가 붙어야 한다.
# 2. 행과 열 번호로 확인
sheet1.cell(row=1, column=1).value   # 인수 위치 주의. 그냥 키워드 인수로 찾는게...?

# 열 값들 출력하는 법                     # 엑셀은 0이 아니라 1부터 시작
for f in range(1, sheet1.max_row + 1):   # .max_row로 최대 범위를 지정한다.
	print(sheet1.cell(row=f, column=1).value) # 행과 열 번호로 호출
    
# 셀 이름으로 호출하는 법(꽤 마음에 든다.)
for f in range(1, sheet1.max_row + 1):
	print(sheet1[f'A{f}'].value)       # f-string 활용. 직관적이다.

 

 

  • 쓰기, 확장하기, 수정하기

기본적으로 딕셔너리데이터프레임처럼 위치만 불러온다고 수정할 수 있진 않고,

.value로 값을 따로 호출해서 재선언해야한다.

# 1번 행 수정
sheet2['A1'] = 'Pineapple'
sheet2['B1'] = 'yellow'

# 마지막 행에 값 추가
sheet2['A4'] = 'Orange'
sheet2['B4'] = 'orange'

# 하드코딩이 싫어서 다르게 해 본 것
sheet2.cell(row = sheet2.max_row+1, column=1).value = 'Orange'
sheet2.cell(row = sheet2.max_row, column=2).value = 'orange'
             ## 10번에서 4행이 이미 생겨나서, 11번에는 max_row만 옴
             ## 이게 번잡해서 찾아보니 next_row라는 키워드가 있더라.
             
# 추가할 것들 리스트 작성
fruits = ['Strawberry', 'Grape', 'Kiwi']
colors = ['red', 'purple', 'green']

# for문으로 추가하기
x = 0
for f in range(1, 8):   ## 위에 말한 max_row의 유동성 문제로 결국 하드코딩   
    sheet2[f'A{f}'] = fruits[x]
    sheet2[f'B{f}'] = colors[x]
    x += 1

for i in range(1, sheet2.max_row + 1):
    print(sheet2.cell(i, 1).value, sheet2.cell(i, 2).value)
    
# 강사님 정답
fruits = [['Strawberry', 'red'], ['Grape', 'purple'], ['Kiwi', 'green']]  # 2차원 리스트 사용
start = sheet2.max_row + 1

for i in range(0, 3):  # 이걸 len(fruits)으로 하면 안돌아간다.
                       # 당연하지 int인데.
    for j in range(0, 2):
        sheet2.cell(i+start, j+1).value = fruits[i][j]

wb.save('Fruit4.xlsx')

# C열 값추가 (0-6)
for j in range(1, 8):    # 여기도 범위는 하드코딩
    sheet2[f'C{j}'] = j - 1

# A열 소문자화, B열 앞 3자리까지 표시
for i in range(1, sheet2.max_row + 1):
    print(sheet2.cell(i, 1).value, sheet2.cell(i, 2).value, sheet2.cell(i, 3).value)

wb.save('Fruit5.xlsx')

 

또 포스팅하다 말고 이것저것 실험하다 보니 시간이 녹았다. 허리도 살살 녹는다.

 

내일부터 데이터 탐색이다. 힘내자.

 

AICE 이달 말에 있다. 도전해보자.

 

화이팅 나자신.