오늘은 데이터 다루기 마지막 날.
파이썬이 외부의 파일이나 프로그램과 어떤 식으로 상호작용하는지를 배웠다.
데이터분석 전반에서 많이 쓰이지는 않지만, 파이썬의 확장성을 체험해볼 수 있었다.
목차
- 파일 읽고 쓰기
- 워드클라우드 만들기
- 엑셀 파일 다루기
- 이메일 보내기
파일 읽고 쓰기
말 그대로 외부 파일을 읽고 쓰고 수정하는 법.
데이터분석 플로우에서는 pandas의 내장 함수 read_csv나 read_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으로 되어 있다.
제외 대상은 일단 마구잡이로 불필요해 보이는 걸 찾아 썼다.
워드클라우드를 여러 번 그려 가며 하니 찾기 쉬웠다.
그 결과물
워드클라우드의 핵심은 키워드의 가시성이라고 생각한다.
내가 사용한 글은 BBC의 IT 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 이달 말에 있다. 도전해보자.
화이팅 나자신.