오늘의 공부 복기! 파이썬
파이썬으로 디비에 있는 데이터 불러와서 가공하고 원하는 결과를 csv로 뽑아보려 했습니다.
작업은 주피터 환경에서 해봤어요.
참고로 비전공자... 그냥 취미로 코딩하는 정도라.. 엄청 엉망일 수 있음 주의하셔야 합니다..
from pandas.io.sql import DatabaseError
import pymysql
import pandas as pd
import numpy as np
#db 연결
conn = pymysql.connect(host= "호스트", user="유저명", password="비밀번호", db="db이름", charset="utf8")
curs = conn.cursor()
office_list = '쿼리문'
curs.execute(office_list)
office_df = pd.read_sql_query(office_list,conn)
office_new_list = '쿼리문'
curs.execute(office_new_list)
office_new_df = pd.read_sql_query(office_new_list,conn)
conn.commit()
conn.close()
#데이터 프레임 2개 합치기
total_office_df = pd.concat([office_df,office_new_df], ignore_index=True)
파이썬 디비 연결은 pymysql을 사용했습니다.
연결 후에 쿼리문을 각각 돌리고 pd.concat을 활용해서 2개를 합쳤습니다.
합칠 때, ignore_index를 해줬습니다.
요걸 해주면 index를 합쳐진 데이터 기준으로 0부터 쭈욱 정리해줍니다.
안해주면 office_df의 인덱스 다음에 오는 office_new_df의 인덱스가 0부터 다시 쌓여서 0이 2개, 1이 2개 이런 식으로 되기 때문에 나중에 데이터 프레임으로 작업이 불가능하여 index를 아예 갱신해줬습니다.
#중복값 제거, 제거 후 인덱스 갱신, live_yn 열 추가
total_office_df = total_office_df.drop_duplicates(['id'])
total_office_df.reset_index(drop=True,inplace=True)
total_office_df['live_yn']=0;
그 다음에는 합쳐봤더니 중복되는 id 값들이 보여서 id라는 특정 열을 기준으로 중복값을 제거해줬습니다.
중복값을 제거했더니 인덱스값이 80 다음에 83 이런식으로 나와서 다시 한번 reset_index를 사용하여 인덱스를 정리해줬습니다.
drop을 true로 둬야 열을 유지해주고 그냥 0부터 숫자를 배정해줘서 넣었고 inplace를 해줘야 total_office_df가 원하는 인덱스 갱신 효과가 있어서 넣어줬습니다. (inplace 안하면.. 다시 total_office_df 봤을 때, 인덱스가 정리 안된 채로 있더라구요)
마지막으로 오피스가 살아있는지를 보고 싶어서 하는 거라 일단 디폴트로 새로운 live_yn 열을 추가한 다음에 전부다 0이라는 값을 부여했습니다.
conn = pymysql.connect(host= "호스트", user="유저명", password="비밀번호", db="db이름", charset="utf8")
curs = conn.cursor()
office_df2 = total_office_df.copy()
for index, row in total_office_df.iterrows():
live_query = '쿼리문'.format(row['id'])
curs.execute(live_query)
live_df = pd.read_sql_query(live_query,conn)
if (live_df.empty==False):
x = 1
else:
x = 0;
office_df2['live_yn'][index] = x;
conn.commit()
conn.close()
위에서 db 연결을 한번 끊었어서 다시 db 연결을 했습니다.
id 정리한 것을 기준으로 id가 들어있는 오피스가 살아있는지를 반복문으로 돌려봤어요.
iterrows()는 행을 반복해주는 함수여서 total_office_df의 행을 0부터 끝까지 반복해줍니다.
이때 index에는 0부터 해당 데이터프레임의 마지막 인덱스 번호까지가 들어가고 row에는 해당 행의 데이터프레임에 담겨져 있는 데이터들이 다 들어있어서 row['id']처럼 부를 수도 있고 row[0] 이런 식으로도 호출이 가능합니다.
저는 이게 살아있는지를 돌려보고 싶었어서 db에서 추출했는데 아예 값이 없는 걸로 나오는지, 아닌지를 if문으로 분기를 태웠습니다.
데이터프레임.empty == false는 데이터프레임이 비어있지 않다. 적어도 제가 추출하고자 했던 데이터가 1개 이상은 있다는 의미입니다. 그래서 해당 경우는 x=1이라는 값을 줬습니다. 그렇지 않으면 0을 줬구요.
여기서 열심히 해보다가 못찾은게 ㅜㅜ copy 활용하는 방법인데..
A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
이런 워닝?이 나오더라구요 ㅜㅜ copy()이걸 어케 쓰면 안나온다고 인터넷에 나오던데.... 제 코드에서는 이걸 없애질 못했습니다.... 나중에 다시 도전해보겠습니다..
어쨌든.. 이렇게 하고서 live_yn 열에 값이 잘 반영됐는지를 value_counts() 함수를 사용해서 확인했습니다.
1을 부여한 값이 85개 확인되었습니다. 만족...
노가다로 확인해봤는데 값은 일단 잘 나온 것 같습니다^^
office_df2.to_csv('결과.csv', index=False)
기분 좋게 마무리로... csv 저장합니다.
데이터프레임.to_csv하고 이름을 저렇게 따옴표 안에 ㅇㅇ.csv로 하면 저장이 잘 됩니다.. 그리고 뒤에 index는 false하면 인덱스 번호 빼고 csv가 저장됩니다.
오늘의 공부 복기 끝!
'스터디 다이어리 > 하루하루 기록' 카테고리의 다른 글
입금 내역에서 8월 큐티 구매자 자동으로 체크해보기 (0) | 2022.08.01 |
---|
입금 내역에서 8월 큐티 구매자 자동으로 체크해보기
오늘의 스터디
교회서 청년부 회계 일을 하는데.. 입금자 명단 비교하는게 귀찮아서.. 함수로 할 수도 있지만 더 난이도 있는 구분까지 해내고자.. 직접 스크립트를 짜보려고 합니다.
실제 사용 중인 출납부..
큐티 구매자랑 비교를 해보려면..
해당 월에 구매했는지를 알 수 있도록 날짜 정보,
'큐티'라는 특정 항목을 체크해야 하니까 계정 정보,
모자이크 처리했지만 구매량에 따라 입금액이 달라지니까 수입 정보,
마찬가지로 누군지를 비고에 표시했기에 비고 정보
이렇게 4가지 정보를 실제 구매자 명단이랑 자동으로 비교하면 될 것 같습니다.
날짜부터 시작합니다..
먼저 짠 코드 공유!
let sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('전체 출납부');
let data = sheet.getRange("b:b").getValues()
let start_date = new Date('2022/7/31')
let start_month = '8월'
let i
for(i=0; i<data.length; i++){
let compare_date = new Date(data[i][0])
if(compare_date.getTime()===start_date.getTime()){
break;
}
}
처음에는 전체 출납부에서 전체 정보를 다 긁어와서 돌릴까 했는데 생각보다 양이 너무 많아서 차라리 필요한 달의 정보만 가서 체크할 수 있도록 짜면 어떨까 생각이 들었습니다.
데이터 볼륨을 최소화 하여.. b열의 날짜 값들만 가져오고 8월 큐티 입금 받기 시작한 날인 '2022/7/31'을 start_date로 정의합니다.
start_month는 그냥 8월 큐티 신청을 할거고.. 큐티 신청 시트에는 해당 월을 8월이라고만 해놔서 저렇게 일단 적어만 둡니다.
그리고선 전체 날짜 데이터 중에서 처음으로 7/31이 나오면 바로 반복문을 멈춰줍니다.
이렇게 하는 이유는 위에서 데이터 범위를 "b:b"처럼 만들듯.. 처음 나온 그 지점을 시작점으로 해서 데이터가 있는 끝점까지의 데이터만 뽑아서 보려고 함입니다.
그 다음 코드!
let start_point = 'b'+(i+1)
let destination = sheet.getRange('b5').getNextDataCell(SpreadsheetApp.Direction.DOWN).getLastRow()
let end_point = 'h'+destination
let new_range = start_point + ':' + end_point
let data_need_checking = sheet.getRange(new_range).getValues()
//Logger.log(data_need_checking)
아까 7/31이 처음 나오는 데이터의 i값이 있을텐데 i는 0부터 시작했기 때문에 1을 더해줍니다.
그리고 그 값을 b와 합쳐줘서 start_point라고 이름 붙였습니다.
destination은 아래 사진과 같이 b열의 마지막 데이터 값이 있는 위치를 체크하기 위해 명명한 값입니다.
엑셀에서도 자주 사용하는 특정 클릭한 후에 단축키(갑자기 기억 안나네요../ 스프레드 시트 기준으로는 ctrl + ↓)로 맨 아래 값이 있는 곳까지 가는 역할을 해줍니다.
저는 h열에 있는 데이터까지 보고 싶었어서 end_point라고 이름 붙이고 h에 destination값을 붙여서 끝값을 만들었습니다.
엑셀이나 스프레드 시트 자주 쓰시는 분들은 뭘 하려는지 아시겠지만.. 간단히 설명하면 아래와 같이 범위를 만들어주려고 했습니다.
제가 보고 싶은 7/31 시작하는 지점부터 그 이후 마지막 기입된 데이터까지를 전부 범위로 잡았다고 보시면 됩니다.
data_need_checking에 들어간 값은 그 특정 범위 내에 있는 날짜, 계정, 적요 ...... 비고까지의 정보가 다 들어 있습니다.
이렇게 한번 가공을 해주고 나면 양이 훨씬 줄어들어서 아래와 같이 이제 직접 원하는 값을 찾아봅니다.
let buyer_info = []
let j
for(j=0;j<data_need_checking.length;j++){
if(data_need_checking[j][1]==='큐티'){
buyer_info.push([data_need_checking[j][3],data_need_checking[j][6]])
}
}
Logger.log(buyer_info)
buyer_info라는 배열을 만들어두고 큐티를 포함하고 있는 행의 값 중 제가 보고 싶은 금액과 이름만 받아봅니다.
그리고 마지막에 buyer_info를 출력해봄으로써 결과가 어케 나왔는지도 확인해봤습니다.
오늘은 여기까지 작업해봤습니다.. 가능한 빨리 또 다시 이어서 작업해보겠습니다.
오늘의 배운 점
자바스크립트 날짜 비교하기
https://www.delftstack.com/ko/howto/javascript/how-to-compare-two-dates-with-javascript/
JavaScript에서 두 날짜를 비교하는 방법
이 기사는 JavaScript에서 두 날짜를 비교하는 다양한 방법을 보여줍니다.
www.delftstack.com
날짜끼리 등호로 비교를 십분 정도? 비교하다가 계속 false만 나와서.. 찾아보니 날짜는 바로 비교가 안되고.. 여러가지 다른 방법으로 비교를 해야 하더라구요.. 하나 배웠습니다. 이번에는 그래서 getTime()을 사용했습니다.
'스터디 다이어리 > 하루하루 기록' 카테고리의 다른 글
오늘의 공부 복기! 파이썬 (0) | 2022.08.01 |
---|