[Python] 파일 입출력 따라하기(xlsx,csv 등)

파이썬으로 파일 입출력을 해보자. csv, xlsx 등 다양한 파일들의 입출력을 배워보자.



csv, xlsx등 파일 입출력(관리)

1. OS 모듈

OS 모듈 준비물

OS 모듈은 아마 기본 내장되어 있을거임.

기본 import

import os


간단한 경로지정 방법(참고)

  • 상대경로(VScode-자바스크립트의 경우..)

    • . 한개 : 한단계 아래 디렉토리를 의미
    • .. 두개 : 한단계 위의 디렉토리를 의미
    <!-- 상대적인 경로(현재 경로에서 찾아가는,,) -->
    <!-- JSCRIPT폴더 -> html폴더 -> index.html파일이 현재 실행파일이며 현재경로이다. -->
    <!-- JSCRIPT폴더 -> hw폴더 -> hw2_1.js파일이 존재하는 상태 -->
    <script type="text/javascript" src="..\hw\hw2_1.js"></script>
    
  • 절대경로

    # 절대적인 경로
    path_dir = 'C:\\Users\\KoBongHun\\Downloads'
    path_dir = 'C:/Users/KoBongHun/Downloads'
    
    # 라이브러리 활용
    import os
      
    simp_path = 'demo/which_path.docx'
    abs_path = os.path.abspath(simp_path) # abspath() 이용해서 절대경로 가져오기
      
    print(abs_path)
    # abspath() 함수의 출력은 현재 작업 디렉토리에 상대적인 절대 경로의 문자열 값을 반환합니다.
    ++
    # 아래 코드 실행시 내 위치가 어디든, 해당 파이썬 스크립트 파일의 절대경로를 구할 수 있다.
    path = os.path.dirname(os.path.abspath(__file__)) 
    print(path)
    


OS 사용법

파일 경로의 원하는 파일들 리스트로 반환

file_list = os.listdir(path_dir) # 해당 경로 파일들 이름 리스트로 반환
  • endswith는 기본 내장함수(str의)

    [file for file in file_list if file.endswith('.csv')] # file_list의 경로의 '.csv'확장자 파일들 리스트로 반환
    


경로존재 확인 및 폴더 추가

os.mkdir('경로 이름') # 폴더추가 메소드
os.path.exists('경로 이름') # 존재 확인
if not os.path.exists('경로 이름'): # 경로 없다면 그 경로(폴더)를 만드는 구조이다.
	os.mkdir('경로 이름')


파일 삭제

os.remove(r"C:\Users\..경로...\product_jinnyhands.xlsx") # 삭제


응용

  • 원하는 경로에 ‘.csv’확장자 파일 발견 할때까지 무한 반복.

    file_list_csv = []
    while(len(file_list_csv) == 0): # 이건 반드시 다운로드폴더에 csv파일 없다는 가정.
        path_dir = 'C:\\Users\\KoBongHun\\Downloads'
        file_list = os.listdir(path_dir)
        file_list_csv = [file for file in file_list if file.endswith('.csv')]
    
  • 보통 파일 삭제 방법.

    try:
       os.remove(r"C:\Users\..경로...\product_jinnyhands.xlsx") # 삭제
    except FileNotFoundError:
       print("product_jinnyhands.xlsx 없음.")
    



2. Workbook(xlsx) 모듈

Workbook 준비물

기본 import

from openpyxl import Workbook # 데이터 쓰기에 사용
from openpyxl import load_workbook # 데이터 읽기에 사용


Workbook 사용법

데이터 쓰기(write)

# 엑셀파일 생성(쓰기)
wb = Workbook()
# 이름이 있는 시트를 생성
ws = wb.create_sheet('생성시트')
# Sheet1에다 입력
ws = wb.active
ws['A1'] = '숫자'
# 행 단위로 추가
ws.append([1,2,3])
# 셀 단위로 추가
ws.cell(5, 5, '5행5열')
# 저장
wb.save("product_jinnyhands.xlsx")
# 종료
wb.close()


데이터 읽기(read)

# data_only=True로 해줘야 수식이 아닌 값으로 받아옴. (엑셀에 함수나오는 그거 얘기임)
wb = load_workbook("product_jinnyhands.xlsx", data_only=True)
# 시트 이름으로 불러오기 
ws = wb['Sheet1']
# 활성화된 sheet로 불러오기
ws = wb.active
# 셀 주소로 값 출력
print(ws['B2'].value)
# 셀 좌표로 값 출력(3행 2열의 값)
print(ws.cell(3, 2).value)

# 지정한 셀의 값 출력
get_cells = ws['B3' : 'B6']
for row in get_cells:
	for cell in row:
		print(cell.value)

# 모든 행 단위로 출력
for row in ws.rows:
	print(row)

# 모든 열 단위로 출력
for column in ws.columns:
print(column)

# 모든 행과 열 출력
all_values = []
for row in ws.rows:
	row_value = []
	for cell in row:
		row_value.append(cell.value)
	all_values.append(row_value)
print(all_values)
# 종료
wb.close()


부가정보

  • 최대 행 구하기

    ws.max_row # 최대행 구함.
    for i in range(1, ws.max_row+1): # 이런식으로 응용. (1행 부터 마지막행 접근 i)
    



3. CSV 모듈

CSV 준비물

기본 import

import csv


CSV 사용법

csv Open(오픈) 방법

  • ‘r’ 형식 (read)

    • reader = csv.reader(d) : 기본적으로 객체 생성방식

    • 아래 예시는 csv파일 읽어서 xlsx로 저장,,!(응용한것)

    # Workbook은 저장위해 그냥 예시로 사용하겠다.
    wb = Workbook()
    ws = wb.active
    with open('jinnyhands.csv', 'r') as d: # with로 물론 안해도됨.
        for row in csv.reader(d): # 한 행씩.. 결국 전체다 저장
            ws.append(row)
    # with방법 말고는 아래.
    f = open('data.csv', 'r', encoding='utf-8')
    rdr = csv.reader(f)
    for line in rdr:
        print(line)
    f.close() 
    
  • ‘a’ 형식 (append) => 당연히 없으면 파일 ‘w’처럼 만들어지며, 추가하는것! (String형식 사용)

    • writer = csv.writer(d) : 기본적으로 객체 생성방식
    with open('nothing_jinnyhands.csv', 'a', newline='') as d:
        writer = csv.writer(d)
        writer.writerow(nothingList[i]) # 데이터또한 배열로 감싸둔 상태꺼 사용(2중배열)
    
  • newline, write방식과, 배열로 저장해야,, (물론 다른방식도 있을거지만 내가 한 방식 토대로..)

    • newline=’‘을 통해서 데이터 저장시 ‘한줄’ 자동으로 넘기는데 그부분을 제거. ‘\n’제거 느낌이죠.

      ########## 출력형식
      # 1. newline='' 안했을시
      데이터1
          
      데이터2
      # 2. newline='' 적용시
      데이터1
      데이터2
      
    • write방식 (writerow, writerows)

      # writerow (주로 사용) : 한줄(한행)에 데이터 출력.
      writer.writerow(dataList)
      # writerows : 한행출력 후 다음행에 출력,, 반복해서 데이터 출력.
      writer.writerows(dataList)
      
    • 데이터 저장 방식(배열 추천) => 2번 4번 형식 주로 사용중!

      dataList = ['1234', 'aaadsf']
      datasList = [['1234'], ['aaadsf']]
      string = 'asdf'
      ##### 데이터 선언후
      writer.writerow(string) # 1. str데이터 기본 사용하며 a,s,d,f 이런식으로 저장.
      writer.writerow(dataList) # 2. []로 넣어서 1234,aaadsf 이런식으로 저장.(정상)
      writer.writerow(dataList[0] # 3. []의 요소 접근함으로 1번처럼 str 형식으로 저장.
      writer.writerow(datasList[0]) # 4. 2중[]임으로 요소접근해도 []접근!! 2번과 동일한 출력.(정상)
      


응용(네이버 시가총액 기록,,)

  • 새로보는 함수 : strip() : 불필요한 문자 삭제
import csv
import requests
from bs4 import BeautifulSoup

url = "https://finance.naver.com/sise/sise_market_sum.nhn?sosok=0&page="

filename = "시가총액1-200.csv"
f = open(filename, "w", encoding="utf-8-sig", newline="") # utf-8-sig는 엑셀 한글깨질때 적용해주면 됌
writer = csv.writer(f)

title = "N	종목명	현재가	전일비	등락률	액면가	시가총액	상장주식수	외국인비율	거래량	PER	ROE".split("\t")
# 출력 : ["N", "종목명", "현재가", ...]

writer.writerow(title) # 데이터 쓰기

for page in range(1,5):
    res = requests.get(url + str(page))
    res.raise_for_status()
    soup = BeautifulSoup(res.text, "lxml")

    data_rows = soup.find("table", attrs={"class":"type_2"}).find("tbody").find_all("tr")
    for row in data_rows:
        columns = row.find_all("td")
        if len(columns) <= 1: # 의미없는 데이터 skip
            continue
        data = [column.get_text().strip() for column in columns] # 한줄for문 and strip으로 불필요한 문자열 없앰
        # print(data)
        writer.writerow(data) # 데이터 쓰기



4. Pandas(xlsx,csv) 모듈

pandas 준비물

외부 모듈 설치

pip install pandas


기본 import

import pandas as pd # pandas의 경우 보통 pd로 이름변경해서 사용하는것이 관례임.


pandas 사용법

함수들

  • 상위, 하위 호출(head, tail)

    print(df.head(10)) # 명령어를 호출하여 상위 10개의 데이터를 불러옵니다.
    print(df.tail(10)) # 하위 출력
    
  • 차원(486 rows × 29 column), 통계(shape, describe)

    # 2차원 행렬로 구성된 데이터 프레임의 크기 출력 ( number_of_rows, number_of_columns )
    print(f"차원 수 : {df.shape}") # 행 x 열
    print(f"행의 수 : {df.shape[0]}") # 행
    print(f"열의 수 : {df.shape[1]}") # 열
    print(df.describe()) # 데이터프레임의 표현적인 통계(descriptive statistics) 보기
    
  • df에 원하는 필드와 원하는 레코드만 df_sub로 저장

    df_sub = df[['역번호','역명','구분','08시-09시']]
    df_sub = df_sub[30000:40000]
    
  • ‘구분’에 따른 평균,최대,최소 구하기(= ‘구분’에 그룹화 후 평균,최대,최소)

    print(df_sub.groupby(['구분'],as_index=True).mean()) # mean() 평균
    # print(df_sub.groupby(['구분'],as_index=True).min()) # min() 최소
    # print(df_sub.groupby(['구분'],as_index=True).max()) # max() 최대
    
  • 특정 컬럼값을 만족하는 데이터프레임을 출력하기(loc, iloc)

    df.loc[df['column_name'] == some_value]
    # ex) 하단역(102)에 대한 승하차정보만 갖게 필터링
    df_hadan = df.loc[df['역번호'] == 102]
    # ex) 두 가지 이상의 필터를 혼합
    df_hadan_sub = df_hadan.loc[(df_hadan['08시-09시'] >= 1000) & (df_hadan['18시-19시'] >= 2000)]
      
    # df.iloc[start_row:end_row, start_col:end_col]
    mr.iloc[:,1:2] # mr은 df형식
    mr.iloc[:,0:2] # 이 열만 보여줌
    mr[1:2] # 이 행만 보여줌
    
  • 행, 열 교환(Transpose 메소드)

     df.T
    
  • 열 이름 바꾸기(rename)

    usa_airports = ~~.loc[:,[1,4,6,7]] # df로 구성된 usa_airports
    usa_airports.rename(columns={1: 'name', 4: 'id', 6: 'latitude', 7: 'longitude'}, inplace=True)
    
  • 리스트로 변환

    listA = dfA.values.tolist() # 데이터프레임의 값들을 tolist()한다.
    
  • 해당 데이터에 원하는 값이 있는지 찾기

    src = usa_airports[usa_airports.name.str.contains('San Francisco International Airport')]
    # 더 나아가서 공항 이름 찾은 행 데이터 src를 공항코드로 접근하기
    src = src.iloc[:,1].values[0] # 공항코드 값으로 변경
    


csv->xlsx (read_csv(), to_excel()) : csv읽기, 엑셀로 변환

  • read_csv()

    md = pd.read_csv('부산교통공사_시간대별 승하차인원_20210801.csv', encoding='cp949')
    
    • 속성들 : header, encoding, low_memory… 등

      header=None으로 속성을   있다.
      encoding='cp949'
      low_memory=False
      
  • 우선 ExcelWriter메소드 사용을 위해 xlsx파트에서 import 따라하기.
  • Workbook + Pandas인 응용이라 생각하면 됨.
# encoding은 항상 고려해줘야함. (한글이 깨질 수 있기 때문)
md = pd.read_csv('부산교통공사_시간대별 승하차인원_20210801.csv', encoding='cp949')
writer = pd.ExcelWriter('product_jinnyhands.xlsx') # 이때 엑셀 만들어짐.

md.to_excel(writer, index = False) # 엑셀에 데이터 삽입
writer.save() # 엑셀 데이터 저장


집합 연산

UNION(합집합)

  • 두가지 방법 이상이 기대될수 있다. 1) pd.concat을 사용하여 데이터프레임을 유지하거나, 2) 각 데이터에 대해 list 형태로 변환한 뒤에 계산하는 방법
# pd.concat 사용

union_commute = pd.concat([P, S], ignore_index = True) # pd.concat을 이용해 P, S를 합할수 있다. ignore_index를 통해 행 인덱스 번호도 재배열!
union_commute = union_commute.drop_duplicates() # drop_duplicates메소드를 이용해 중복값 제거를 할 수 있다.


INTERSECTION(교집합)

  • pd.concat은 outer로 join이 기본값으로 되어있으므로 합집합이 나온다.(outer:합집합, inner:교집합) 따라서 join을 inner로 바꿔주거나, merge함수를 사용해주면 된다.(merge의 기본값은 inner)
# pd.merge 사용

intersection_commute = pd.merge(P, S)


DIFFERENCE(차집합)

  • isin메소드 이용
P_only = P[P.index.isin(S.index) == False]
S_only = S[S.index.isin(P.index) == False]



Workbook() 자세히 따라하기

1. create_file

준비물

from openpyxl import Workbook


사용법

wb = Workbook() # 새 워크북 생성
ws = wb.active # 현재 활성화된 sheet 가져옴
ws.title = "NadoSheet" # sheet 의 이름을 변경
wb.save("sample.xlsx") # 저장
wb.close() # 닫기

# 기본 open()메소드 이용한 방법
file = open("./hello.xlsx", "w+") # 엑셀로 만들어도 됨
file.write("hello" + "\n") # 이런식으로도 엑셀,csv 저장가능! ! !


2. sheet(시트)

sheet 생성방식

  • create_sheet() : 생성

    ws = wb.create_sheet() # 새로운 sheet 기본 이름으로 생성
    ws1 = wb.create_sheet("YourSheet") # 주어진 이름으로 sheet 생성
    ws2 = wb.create_sheet("NewSheet", 2) # 2번째 index에 sheet 생성
    
  • copy_worksheet() : 복사

    # sheet 복사
    new_ws["A1"] = "Test" # 임의로 [A1]셀에 Test기입
    target = wb.copy_worksheet(new_ws)
    target.title = "Copied Sheet"
    


sheet 이름변경, 이름확인, 색상적용

  • .title : 제목변경

    ws.title = "MySheet" # sheet 이름 변경
    
  • sheet_properties.tabColor : 색상변경

    ws.sheet_properties.tabColor = "ff66ff" # RGB 형태로 값을 넣어주면 탭 색상 변경
    
  • .sheetnames : 이름 확인

    print(wb.sheetnames) # 모든 sheet 이름 확인
    

sheet 접근(Dict형태)

new_ws = wb["NewSheet"] # Dict 형태로 sheet 에 접근


3. cell(셀)

셀에 값 입력

# A1 셀에 1 이라는 값을 입력(전부동일)
ws["A1"] = 1
ws["A1"].value = 1
ws.cell(1,1).value = 1 # ws.cell(row=1, column=1).value
ws.cell(1,1,1) # ws.cell(column=1, row=1, value=1)


셀 정보, 값 출력

ws["A1"] # A1 셀의 정보를 출력
ws["A1"].value # A1 셀의 '값'을 출력, 값이 없을 땐 'None' 을 출력
ws.cell(1,1) # 정보출력(동일)
ws.cell(1,1).value # 값 출력(동일)


4. open_file(파일 load)

준비물

from openpyxl import load_workbook


사용법

from openpyxl import load_workbook
wb = load_workbook("sample.xlsx")
ws = wb.active

# cell 데이터 불러오기
for x in range(1, 11):
    for y in range(1, 11):
        print(ws.cell(row=x, column=y).value, end=" ") # 1 2 3
    print() # 줄바꿈

# cell 개수 모를때 (max_row or max_column을 이용!)
for x in range(1, ws.max_row + 1):
    for y in range(1, ws.max_column + 1):
        print(ws.cell(row=x, column=y).value, end=" ") # 1 2 3
    print()


5. cell_range(셀 주소)

1줄씩 데이터 넣기

ws.append(["번호", "영어", "수학"]) # A, B, C열 순서로 적용
for i in range(1, 11):
    ws.append([i, randint(0, 100), randint(0, 100)])
1	92	59
2	67	12
... 이런식으로 적용.


다양한 데이터 가져오는 방식

ws["B"] # B열 가져오기.
ws["B:C"] # B,C열 가져오기.
ws[1] # 1번째 행 가져오기.
ws[2:6] # 2행부터 6행까지 가져오기.

# 전체 rows
print(tuple(ws.rows)) # 한줄씩 가져와서 튜플로 ((<~>,<~>,,),(<~>,<~>,,)..)
for row in tuple(ws.rows): # row : (<~>,<~>,,)
    print(row[2].value) # 따라서 [2]는 row의 2번째 index 요소꺼 가져옴.

# 전체 columns
print(tuple(ws.columns)) # 한열씩 가져와서 튜플로
for column in tuple(ws.columns):
    print(column[0].value)

# 위와 동일 iter_rows(), iter_cols()
for row in ws.iter_rows(): # 전체 row
    print(row[2].value)

for column in ws.iter_cols(): # 전체 column
    print(column[0].value)

# 2번째 줄부터 11번째 줄까지, 2번째 열부터 3번째 열까지
for row in ws.iter_rows(min_row=2, max_row=11, min_col=2, max_col=3):
	print(row[index].value)


6. search(검색)

for row in ws.iter_rows(min_row=2):
    # 번호, 영어, 수학
    if int(row[1].value) > 80:
        print(row[0].value, "번 학생은 영어 천재")

for row in ws.iter_rows(max_row=1):
    for cell in row:
        if cell.value == "영어":
            cell.value = "컴퓨터"
            
# 물론 예시일뿐 이방법으로만 접근할 수 있다는 의미는 아니다. 다양한 방식으로 접근 가능하다.


7. insert(추가)

행삽입, 열삽입

ws.insert_rows(8) # 8번째 행추가.
ws.insert_rows(8, 5) # 8번째 행기준 5행 추가

ws.insert_cols(2) # 2번째 열
ws.insert_cols(2, 3) # 2번째 열기준 3열 추가


8. delete(삭제)

행삭제, 열삭제

ws.delete_rows(8) # 8번째 행 데이터 삭제
ws.delete_rows(8, 3) # 8번째 행부터 총 3행 삭제

ws.delete_cols(2) # 2번째 열 데이터 삭제
ws.delete_cols(2, 2) # 2번째 열부터 총 2열 삭제


9. move(이동)

데이터 다른셀로 이동

ws.move_range("B1:C11", rows=0, cols=1) # B1:C11이 0행 1열 간 것. (1열 옆으로 한칸 옮)


10. chart(차트)

준비물

from openpyxl.chart import BarChart, Reference, LineChart


사용법

# B2:C11 까지의 데이터를 차트로 생성
bar_value = Reference(ws, min_row=2, max_row=11, min_col=2, max_col=3)
bar_chart = BarChart() # 차트 종류 설정 (Bar, Line, Pie, ..)
bar_chart.add_data(bar_value) # 차트 데이터 추가
ws.add_chart(bar_chart, "E1") # 차트 넣을 위치 정의

# B1:C11 까지의 데이터
line_value = Reference(ws, min_row=1, max_row=11, min_col=2, max_col=3)
line_chart = LineChart()
line_chart.add_data(line_value, titles_from_data=True) # 계열 > 영어, 수학 (범례부분)
line_chart.title = "성적표" # 제목
line_chart.style = 20 # 미리 정의된 스타일을 적용, 사용자가 개별 지정
line_chart.y_axis.title = "점수" # Y축의 제목
line_chart.x_axis.title = "번호" # X축의 제목
ws.add_chart(line_chart, "E1")


11. cell_style(셀 스타일)

준비물

from openpyxl.styles import Font, Border, Side, PatternFill, Alignment


사용법

데이터 셋,,,

a1 = ws["A1"] # 번호
b1 = ws["B1"] # 영어
c1 = ws["C1"] # 수학


속성

  • column_dimensions[] : 행 or 열의 노비나 넢이 설정

    # A 열의 너비를 5로 설정
    ws.column_dimensions["A"].width = 5
    # 1 행의 높이를 50으로 설정
    ws.row_dimensions[1].height = 50
    
  • font : 스타일 적용

    a1.font = Font(color="FF0000", italic=True, bold=True) # 글자 색 빨강, 기울임, 진하게
    b1.font = Font(color="CC33FF", name="Arial", strike=True) # strike는 취소선
    c1.font = Font(color="0000FF", size=20, underline="single") # underline은 밑줄
    
  • border : 테두리 적용

    thin_border = Border(left=Side(style="thin"), right=Side(style="thin"), top=Side(style="thin"), bottom=Side(style="thin"))
    a1.border = thin_border
    b1.border = thin_border
    c1.border = thin_border
    
  • alignment : 정렬

    # center, left, right, top, bottom
    a1.alignment = Alignment(horizontal="center", vertical="center") # 상하, 좌우
    
  • fill : 배경 설정

    a1.fill = PatternFill(fgColor="00FF00", fill_type="solid") # 배경 설정
    
  • freeze_panes : 틀 고정

    ws.freeze_panes = "B2" # B2 기준으로 틀 고정
    
  • merge : 병합하기

    ws.merge_cells("B2:D2") # B2:D2 셀을 합침
    ws["B2"].value = "Merged Cell"
    
  • unmerge : 병합 해제하기

    ws.unmerge_cells("B2:D2") # B2:D2 셀 병합을 해제함. => B2,C2,D2로 다시 나뉨.
    


예시

for row in ws.rows:
    for cell in row:
        # 각 cell에 대해서 정렬
        cell.alignment = Alignment(horizontal="center", vertical="center")
        # center, left, right, top, bottom

        if cell.column == 1: # A 번호열은 제외
            continue

        # cell 이 정수형 데이터이고 90점보다 높으면
        if isinstance(cell.value, int) and cell.value > 90:
            cell.fill = PatternFill(fgColor="00FF00", fill_type="solid") # 배경설정
            cell.font = Font(color="FF0000") # 폰트 색상 변경


12. formula(함수사용)

  • data_only=True 속성 : True로 지정해야 수식(함수형태)이 아닌 데이터를 가져옴.

    wb = load_workbook("sam_formula.xlsx", data_only=True)
    

엑셀함수 사용하듯이 그대로 사용!!

ws["A2"] = "=SUM(1, 2, 3)"
ws["A3"] = "=AVERAGE(1, 2, 3)"

ws["A4"] = 10
ws["A5"] = 20
ws["A6"] = "=SUM(A4:A5)"


13. image(이미지 삽입)

  • 만약 ImportError : You must install Pillow to …이면 pip install Pillow 설치 할 것.

준비물

from openpyxl.drawing.image import Image


사용법

img = Image("img.png")

# C3 위치에 이미지 삽입
ws.add_image(img, "C3")

댓글남기기