data analysis & visualization

크롤링의 종류와 개요는 아래에 포스팅 해두었으니, 궁금하신 분은 먼저 읽고 오기를 바란다.

pycj92.tistory.com/16

 

크롤링과 python

크롤링, 스크래핑 데이터 분석의 자료수급을 위해 요즘 같이 활용되는 기술로 크롤링이라 부르는 기술이 있다. 크롤링은 크롤러가 웹을 돌아다니는 작업을 말하고, 스크래핑은 크롤러를 통해

pycj92.tistory.com

사용될 패키지

크롤링에 사용될 패키지는 다음과 같으며, 간단한 용도는 다음과 같다.

자료 저장 경로나 디렉토리조회 관련 용도의 os 패키지
자료 추출을 위한 re 패키지
크롤러에 지연을 주기위한 time 패키지
원하는 곳으로 파일 이동을 위한 shutil 패키지
사용하지는 않았지만, 향후 자동로그인을 위한 threading 패키지
마지막으로 크롤링에 사용되는 selenium 패키지

import os
import re
import warnings
from time import sleep
import pandas as pd
import shutil
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import Select
import threading 

 

사용 환경 설정

본격적인 크롤링에 앞서, 환경을 세팅해보자. 

환경을 세팅하기 위해서는 크롬드라이버를 별도로 다운로드 받아야하는데 사용하고 있는

크롬의 버전과 동일해야 한다. 

아래는 크롬드라이버의 버전을 확인하는 과정이다. 

 

현재 내 컴퓨터는 89.0 버전이라는 것을 확인할 수 있다. 

아래 링크는 크롬드라이버를 설치할 수 있는 사이트이다. 해당 사이트에서 내 버전인 89.0 windows 버전으로 다운받자.

chromedriver.chromium.org/downloads

 

Downloads - ChromeDriver - WebDriver for Chrome

WebDriver for Chrome

chromedriver.chromium.org

다운 받았다면, 다운받은 chromedriver.exe파일을 자주사용하는 경로로 이동시키도록 하자
(나는 c:/selenium으로 설정함, c:/selenium/chromedriver.exe) 

본격적인 크롤링

간략히 설명하자면, driver_path는 chrome driver의 경로를 의미하며, download_path는
인터넷의 자동 다운로드 경로를 의미한다. 

setting함수를 사용하게 되면, 기상자료개방포털 홈페이지로 이동하게 된다.
login 함수를 사용하게 되면, login을 수행하며, 성공하면 True를 반환한다.
logout 함수를 사용하게 되면, logout을 수행하며, 성공하면 True를 반환한다.
close와 quit함수는 인터넷창을 닫는다. 

 

class KMA:
    def __init__(self,driver_path=r'c:\selenium\chromedriver.exe',
    	download_path=r'D:\downloads',options = Options(),time=5):
        self.down_dir=download_path
        self.driv_path=driver_path
        self.options=options
        options.add_experimental_option("prefs", {
            "download.default_directory": self.down_dir})
        self.time=time
        self.thread=threading.Timer(time,self.auto_login)
        
    def setting(self):
        try:
            self.driver.quit()
        except:
            1
        self.driver= webdriver.Chrome(self.driv_path, options=self.options)
        self.driver.get('https://data.kma.go.kr/cmmn/main.do')
        
    def login(self,kma_id,kma_pass):
        try:
            self.driver.maximize_window()
            self.driver.find_element_by_css_selector('a#loginBtn').click()
            self.driver.find_element_by_css_selector('input#loginId.inp').send_keys(kma_id)
            self.driver.find_element_by_css_selector('input#passwordNo.inp').send_keys(kma_pass)
            self.driver.find_element_by_css_selector('button#loginbtn.btn_login').click()
            return True
        except:
            print('이미 로그인 중입니다.')
            return False
    def logout(self):
        try:
            self.driver.maximize_window()
            self.driver.find_element_by_css_selector('a#logoutBtn').click()
            return True
        except:
            print('이미 로그아웃 되어있습니다.')
            return False

    def close(self):
        self.driver.close()
    def quit(self):
        self.driver.quit()
    

login, logout 을 매번 수행하기 귀찮으므로 login_loof함수를 사용하게 되면 다시 로그인을 수행한다.

 

auto_login, start, cancel함수는 현재 수정중이다.

download는 자료를 다운로드 받는 함수이다.
data_type은 지상기상관측자료와 해양자료 즉, Aws, Asos, Agr, FargoBuoy, Buoy, Rh가 될수 있으며,
new_path는 최종적으로 저장될 경로를 의미하고, time_type은 시간자료, 분자료, 일자료 등이 될 수 있다. 

    def login_loof(self,kma_id,kma_pass):
        self.logout()
        self.login(kma_id,kma_pass)
            
    def auto_login(self,kma_id,kma_pass):
        self.login_loof(kma_id,kma_pass)
        self.thread=threading.Timer(self.time,self.auto_login)
        self.thread.start()

    def start(self):
        self.thread.start()

    def cancel(self):
        self.thread.cancel()
        
    def download(self,data_type,download_day,new_path,query,time_type='시간 자료'):
        """ 사이트 이동 """
        try:
            if data_type in ['Aws','Asos','Agr']:#Asos,Aws,Agr
                self.driver.get(f'https://data.kma.go.kr/data/grnd/select{data_type}RltmList.do?pgmNo=')
            elif data_type in ['FargoBuoy','Buoy','Rh']:#data_type='FargoBuoy'#Buoy,lb(Rh),FargoBuoy
                self.driver.get(f'https://data.kma.go.kr/data/sea/select{data_type}RltmList.do?pgmNo=')
            else:
                raise
        except:
            print('Asos, Aws, Agr, FargoBuoy, Buoy, Rh')
        """ 시간 타입 """
        Select(self.driver.find_element_by_id('dataFormCd')).select_by_visible_text(time_type)
        """ 변수 선택 """
        self.driver.find_element_by_id('ztree1_1_check').click()
        
        """ 전체 지점 선택 """
        if self.driver.find_element_by_css_selector('a#ztree_1_check').get_attribute('title')=='전체선택 안됨':
            self.driver.find_element_by_css_selector('a#ztree_1_check').click()
        
        """ 시작 기간 설정 """
        self.driver.execute_script('document.querySelector("input[id=startDt_d]").removeAttribute("readonly")')
        self.driver.execute_script(f'document.querySelector("input[id=startDt_d]").value = "{query}"')
        
        """ 끝 기간 설정 """
        self.driver.execute_script('document.querySelector("input[id=endDt_d]").removeAttribute("readonly")')
        self.driver.execute_script(f'document.querySelector("input[id=endDt_d]").value = "{query}"')
        
        if time_type=='시간 자료':
            self.driver.find_element_by_xpath(f'//select[@name="startHh"]/option[@value="{st_time}"]').click()
            self.driver.find_element_by_xpath(f'//select[@name="endHh"]/option[@value="{ed_time}"]').click()
        
        """ 조회 """
        self.driver.execute_script('goSearch();')
        sleep(1)
        if data_type=='FargoBuoy':
            pd.read_html(self.driver.find_elements_by_css_selector('table.tbl')[0].get_attribute('outerHTML'))
        else:
            pd.read_html(self.driver.find_elements_by_css_selector('table.tbl')[1].get_attribute('outerHTML'))
        
        """ 다운로드 """ 
        self.driver.execute_script('downloadRltmCSVData();')
        sleep(1)
        try:
            self.driver.find_element_by_css_selector('div#divPopupTemp.back_layer').get_attribute('id')
            self.driver.find_element_by_id("reqstPurposeCd7").click()
        except:
            1
        self.driver.execute_script('fnRltmRequest();')
        #A.quit()
        
        before_files=[i for i in os.listdir(self.down_dir) if re.compile('.csv').findall(i)]
        
        before=(len(before_files))
        sleep(5)
        after_files=[i for i in os.listdir(self.down_dir) if re.compile('.csv').findall(i)]
        after=(len(after_files))
        if before!=after:
            down_file=list(set(after_files)-set(before_files))[0]
            shutil.move(f'{self.down_dir}/{down_file}',new_path)

                        

자료를 하루만 받을게 아니라서, download_range함수를 만들었다. 
n_download_login_loof는 '자료를 몇개 받았을 때 재로그인할지'에서 몇개를 의미한다(default : 20)
over_write는 기존에 같은 자료가 있으면, 넘어갈지 덮어쓸지를 의미한다.

    def download_range(self,date_list,data_type,kma_id,kma_pass,\
                       n_download_login_loof=20,st_time='00',ed_time='23',time_type='시간 자료',\
                       down_dir='d:/downloads/aws',over_write=False):
        _n_download_login_loof=0
        down_error=list()
        old_down_dir=os.listdir(down_dir)
    
        for download_day in date_list:
            _n_download_login_loof=_n_download_login_loof+1
            if _n_download_login_loof%n_download_login_loof==1:
                self.login_loof(kma_id,kma_pass)
                sleep(3)
            query=download_day.strftime('%Y%m%d')
            move_file_name=f'{data_type}_{query}_{time_type}.csv'
            new_path = f'{down_dir}/{move_file_name}'
            n_download_login_loof=n_download_login_loof+1

            if over_write==False:
                if not move_file_name in old_down_dir:
                    try:
                        print(download_day)
                        self.download(data_type,download_day,new_path,query,time_type)
                    except:
                        down_error.append(download_day)
            else:
                try:
                    print(download_day)
                    self.download(data_type,download_day,new_path,query,time_type)
                except:
                    down_error.append(download_day)
        return down_error

    def date_to_filename(self,date_list,down_dir, data_type, time_type):
        return [f'{data_type}_{i.strftime("%Y%m%d")}_{time_type}.csv' for i in date_list]


 

대충 사용방법은 아래를 따라하면 된다.

A=KMA(time=60*3,download_path=r'D:\downloads\temp')
#A=KMA(time=60*3)
A.setting()
A.login_loof(kma_id=아이디,kma_pass=비밀번호)
start_day = '2010-01-01';end_day = '2020-12-31';data_type='Asos'#Asos,Aws
st_time='00';ed_time='23';time_type='시간 자료';down_dir='d:/downloads/asos';over_write=False
start_day = pd.Timestamp(start_day)
end_day = pd.Timestamp(end_day)
date_list=pd.date_range(start_day,end_day,freq='d')
#start_day = pd.Timestamp(start_day)
#download_day=start_day 
#query=download_day.strftime('%Y%m%d')
#move_file_name=f'{data_type}_{query}_{time_type}.csv'
#new_path = f'{down_dir}/{move_file_name}'
#A.download(data_type,download_day,new_path)
down_error_list=A.download_range(date_list,data_type,n_download_login_loof=20,\
                                 kma_id=아이디,kma_pass=비밀번호,down_dir='d:/downloads/asos')

#query=download_day.strftime('%Y%m%d')
set(A.date_to_filename(date_list, down_dir, data_type, time_type))-set(os.listdir(down_dir))
A.quit()

 

'python > crawling' 카테고리의 다른 글

크롤링과 python  (0) 2021.04.03
python selenium 자주쓴거 정리  (0) 2020.03.23
나라장터 open api crawling  (0) 2020.03.01
[나라장터] 크롤링  (2) 2019.11.14
selenium 사용해서 위경도 가져오기  (0) 2019.03.20

크롤링, 스크래핑

데이터 분석의 자료수급을 위해 요즘 같이 활용되는 기술로 크롤링이라 부르는 기술이 있다. 

크롤링은 크롤러가 웹을 돌아다니는 작업을 말하고, 스크래핑은 크롤러를 통해 자료를 수집하는 것을 의미한다.

물론 이게 완벽한 정의라고는 할 수 없을지도 모른다.

본론으로 들어가서 크롤링에는 동기식, 비동기식이 있다.

Python에서는 requests, urllib, BeautifulSoup, Selenium, Scrapy 등 이 대표적이다.

크게 웹을 이용하는 selenium을 활용하는 크롤링을 동적크롤링,

requests, urllib, BeautifulSoup을 활용한 크롤링을 정적 크롤링이라고 표현한다.

 

BeautifulSoup, requests, urllib 패키지

해당 패키지는 HTML, XML파일의 정보를 추출해주는 파이썬 패키지이다. 

다소 안정적이고 빠르나, javascript가 필요한 크롤링이 제한된다. 

 

Selenium 패키지

해당 패키지는 인터넷 브라우저를 통해 정보를 추출해주는 패키지이다.

실제 인터넷을 사용하므로, 다소 불안정하나, Javascript가 필요한 크롤링이 수월하다.

 

'python > crawling' 카테고리의 다른 글

[Selenium] 기상자료 크롤링  (1) 2021.04.03
python selenium 자주쓴거 정리  (0) 2020.03.23
나라장터 open api crawling  (0) 2020.03.01
[나라장터] 크롤링  (2) 2019.11.14
selenium 사용해서 위경도 가져오기  (0) 2019.03.20

코딩 스타일은 협업을 잘 하지 않는 내 입장으로써는 다소 생소하지만 중요한 내용이라 할 수 있다.

 

얼마 전 협업을 할 일이 있었는데, 그 때 몇 가지 중요시 해야할 것들을 느끼게 됬다.

 

첫 째, 변수명 및 조건문 표기법 설정둘 째, 중요 서비스 셋 째, 코드 난이도 설정 이 3가지의 중요성을 느꼈다.

 

변수명의 표기법 설정

 

우리가 코딩 할 때에는 여러 변수들을 설정하게 된다.

 

이러한 변수는 그 의미를 파악하기 쉬운 범위 내에서, 짧게 작성하는 것이 좋다.

 

변수 설정 규칙에는 크게 카멜 케이스, 파스칼 케이스, 스네이크 케이스로 나눌 수 있는데, 예를 들어 설명하면,

 

수온이라는 변수가 있다고한다면, Water Temperature라는 단어를

 

카멜 케이스는 waterTemp 혹은 wTemp로 표기,

 

파스칼 케이스는 WaterTemp 혹은, WTemp,

 

스네이크 케이스는 water_temp 혹은 w_temp로 표기한다.

 

카멜 케이스와 파스칼 케이스의 차이는 일반적으로 Class를 표기하는 경우 파스칼 케이스를 사용하며,

 

그렇지 않은 경우 카멜케이스를 사용하도록 한다.

 

조건문의 표기법 설정

 

조건문의 표기법은 크게 2가지로 나누어 진다. BSD 방법, K&R 방법, GNU 방법으로 나뉘는데, 표기는 아래와 같다.

 

중요 서비스 설정

 

얼마전 협업으로 진행하는 서비스는 AI를 현업화 단계까지 적용하는 서비스에 해당하였다. 

 

따라서 서비스의 중요도는 규칙적으로 하루에 한 번 애러없이 실행되는 지속성

 

운영될 컴퓨터에서 문제 없이 동일한 결과가 실행 가능한 재현가능성

 

AI 예측모형의 높은 정밀도를 의미하는 정확도 측면이 중요하게 작용하였다.

 

코드 난이도 설정

 

해당 서비스에서는 높은 정밀도를 위해 여러가지 테스트를 해보고 결과를 도출하여야 하였다.

 

따라서 빠른 결과 도출이 중요하였다. 이에 따라 gpu와 병렬처리 코드들이 많이 활용되었는데, 

 

그 때 당시 내 역량이 부족하여, 협업 코드를 같이 수정할 수 없었다.

 

그리고 결과적으로, 운영될 컴퓨터에서 재현가능하게 하기 위해서 새로 코드를 짜는 과정이 필요했다. 

 

본론으로(코딩 스타일과 자동검사)

 

급할수록 돌아가라는 말이 있다. 

 

이처럼 협업을 위해서는 여러가지 약속들을 정의하고 진행하는 것은 최종적으로 시간을 줄이는 결과를 가져옵니다.

 

협업을 통해 프로젝트를 잘 수행하기 위해서는 따라서 프로젝트의 설계가 몹시 중요하다.

 

프로젝트의 설계와 관리는 잘 알지 못하는 분야라 향후 포스팅을 하는 것으로 하고, 

 

지금부터 다루게 될 내용은 python의 코딩 스타일과 코딩 오류의 자동 검사이다.

 

파이썬의 스타일

 

파이썬 개발자는 PEP 8이라는 스타일 가이드를 만들었다.

 

위와 같은 가이드가 있다. python에는 이미 이러한 가이드를 자동 검사하는 도구들이 있습니다.

 

anaconda.org/conda-forge/pycodestyle

 

Pycodestyle :: Anaconda.org

 

anaconda.org

pypi.org/project/pycodestyle/

 

pycodestyle

Python style guide checker

pypi.org

나는 anaconda를 활용하므로 이를 기반으로 스타일 오류 검사를 진행해 보겠다.

 

conda install -c conda-forge pycodestyle 로 pycodestyle을 설치했다.

 

나는 최근에 짠 코드를 확인하기 위해 D:/stock/2021/stock에 있는 main_1file_gen.py를 확인하여 보았다.

 

몇번 째 줄이 너무 길다. 등의 여러가지 문구들을 반환해 준다. 

 

코딩 오류의 자동검사

 

코딩 오류를 확인해주는 툴은 Pyflakes, Pylint와 Pyflakes와 pycodestyle을 합친 flake8 등이 있다. 

 

Pyflakes의 결과이다. 불필요한 패키지나 문법을 수정해준다.

 

pylint는 PEP8 적합성 또한 확인해 준다. 대신 Pyflake보다 느리다는 단점이 있다.

 

따라서 flake8을 사용하며 flake8은 다양한 플러그인이 존재한다고 한다.

 

누군가에게는 이러한 과정이 다소 불필요하고 의미 없어 보일수도 있다. 

 

나도 그랬던 적이 있다. 제한된 시간 내에 어떠한 업무를 하기에 혼자서는 불가능한 경우가 분명히 존재한다.

 

그것이 공모전나 프로젝트든.. 

 

적어도 지금 나는 이러한 프로젝트의 관리가 잘되어 있으면, 향후 관리를 편하게 해 줄 수 있다고 생각한다.

 

해당 내용은 한빛 미디어 진지한파이썬 책을 참고하였습니다. 

'python' 카테고리의 다른 글

python을 시작하기 전에  (0) 2021.02.27
jupyter kernel 제대로 추가 안될 때  (2) 2021.01.24
python oracle DB 연동  (0) 2020.12.03
offline conda pack spyder설치 에러  (0) 2020.12.01
conda python 경로 인식못할 때  (0) 2020.11.28

python 얘기를 시작하기전에 우선 나는 python을 싫어했다.

 

나는 데이터 분석 업무를 맞고 있는 1년차 직장인이다. 

 

나는 대학교 2학년 때부터 AI 업무를 진행하였다. 그 때 접하게 된 프로그래밍 언어는 R이였다. 

 

이렇게 R언어는 내 분석업무에 주가 되주는 언어가 되었다. 

 

하지만 취업의 문 앞에서 python을 선택할 수 밖에 없었다.

 

취업 당시 R은 통계분석에서는 python보다 강력했으나, 웹 기반 서비스인 shiny는 Django나 Flask 대비 무거웠고,

 

딥러닝쪽에서 조차 힘을 쓰지 못하였었다.

 

내가 싫어했던 이유는 사실 프로그래밍언어가 어려워서가 아니였던 것 같다.

 

자유도 측면에서 python은 거부감이 많이 들었던 것 같다. 

 

파이썬은 개발을 고려한 프로그래밍이라 묵시적인 코딩 규칙들이 있었고,

나는 비전공자라 이러한 코딩 규칙은 전혀 무지하였다.

 

또한 여러가지 분석가가 몰라도 되는 애러 이슈들이 많이 있다. 

 

이외에도 많은 말도안되는 이슈들이 존재한다. 하지만 오늘은 한 블로그에 정리된 문제점을 소개하고자 한다.

 

github.com/pablogsal/python-horror-show

 

pablogsal/python-horror-show

Strange and odd python snippets explained. Contribute to pablogsal/python-horror-show development by creating an account on GitHub.

github.com

해당 블로그에서는 1. python의 정수 객체 처리 문제 2. 메모리 스왑 문제 3. 무한 반복 생성 4. Hashable Object 문제

 

5. Iterator 관련 문제 6. 논리 우선순위 문제 7. 객체 변환 문제 등이 있다. 

 

Python의 정수 객체 처리

 

python은 -5 ~ 256까지의 정수 객체 생성에서는 기존 생성된 메모리를 공유한다.

 

그래서 객체를 생성할 때 매번 다른 메모리에 재할당 되는데 -5~256은 같은 결과가 나타난다.

 

 

 

메모리 스왑

 

python의 메모리 스왑 기능은 매우 강력하므로 많이들 사용한다.

 

하지만 아래와 같이 a, b=b, a format은 안되는데 a=b는 적용이 되는 아이러니한 현상이 나타난다. 

 

* python의 index 함수는 리스트 내에서 특정 값의 위치를 찾아주는 함수이다. 

 

우리는 이러한 현상을 이해하려면 a, b= b, a의 적용 순서를 알아야 한다.

 

a[a.index(1)], a[a.index(2)]= 2, 1은 다음과 같이 기작한다.

index함수는 중복값이 있을 때 맨 처음 나타나는 값만을 return해준다. 

 

따라서 함수가 적용되지 않은게 아니라 같은 값이 있을 때 index함수가 맨 처음 위치값을 반환하므로,

 

결과값이 안바뀐 경우라 할 수 있다. 

 

그래서 입력값이 다른 경우에는 문제없이 적용이 된다.

 

 

무한 반복 생성

 

나는 다중 할당 정도로 생각을 하고 있었는데 propositional logic implications of the statement라고 문법이 있나보다.

 

집합론 관련 논리 내용 같은데 주제와 벗어나는 것 같기도 하고 잘 쓸 자신이 없어서 생략한다.

 

하지만 다중 할당의 순서는 알아두면 좋을 것 같다.

 

a, b={}, 5로 할 당하고(P) a[b]를 {}, 5로 할당(Q)하는 결과를 얻고 싶어한다. 

 

a = b = c 의 형태의 문법은 생각에 왼쪽에서 오른쪽으로 가거나 a=c & b=c형태로 진행 되어야 할 것이라 생각했다.

 

저자는 a=c & b=c를 원했던 것 같다. 우선 아래는 결과다.

 

왜 저렇게 무한 반복이 될까??

 

예상과는 다르게 코드는 위와 같이 진행이 되었다.

 

원했던 결과를 얻으려면 아래와 같이 결국 문법을 나누어 제시하여야 한다.

 

Hashable Object 문제

 

나도 hashable object가 뭔지 잘 몰랐다. 그래서 검색해보니 hash함수에 인자로 들어갈 수 있는 객체들을 의미한다.

 

대충 hash에 object로 올 수 있는 값들은 변경 불가능 한 값들이어야 한다. 

 

즉, int, bool, float, tuple, string, bytes 등은  hash에 object로 올 수 있는 반면,

 

list, dict, set 등은 hash에 object로 올 수 없다.

 

이 얘기를 왜하냐면.. 

 

우리는 dictionary의 key 값으로 unique한 값을 필요로 한다.

 

근데 보다시피 따로는 정수 1도, True 값도, 1.0도 key값으로 올 수 있다. 어찌보면 당연하다.

 

근데 죄다 어디로 사라지는지 모르겠다.

hash 값을 확인해 본 결과 모두 1값을 가졌다. 그래서 덮어써진 것 같다.

 

또한 hash 값이 같아서 ==연산자 결과가 같은 것을 볼 수 있다.

공집합은 모든집합의 부분집합이므로 False

 

all 함수는 object 내에 논리기호 모두 True 값을가져야 True를 반환 아니면, False를 반환하는 함수

 

수학적으로 왜 공집합이 False인지는 아직 이해가 가지는 않는데.. 일단 그래서 코드를 보기로 했다.

 

https://docs.python.org/3/search.html?q=all&check_keywords=yes&area=default

파이썬 공식 문서는 위와 같이 나타났다.

 

만약 입력자료 중 하나라도 not 연산을 했을 때 True가 되면(하나라도 False이면) False를 반환 아니면 True를 반환

 

공집합은 for문 자체가 실행이 안되므로, 그냥 True를 반환한다.

 

공집합은 논리상으로 False를 의미한다.

따라서 

all([])이 True였음에도 불구하고, [[]]는 [True]와 같음에도 False라는 이상한 결과가 나타난다.

 

이는 아래와 같이 코드가 돌기 때문이다.

 

 

이터레이터 관련 이슈

 

해당 이슈는 완전히 이해가 가지 않았으나, 사용도가 높지 않을 것 같아 결과만 첨부하였다.

 

sorted함수는 list를 반환하는데 reversed 함수는 iterator를 반환한다고 한다고 합니다.

 

reversed 함수는첫번째 호출에서 sorted함수를 호출한다고 합니다.  따라서 다음과 같이 공집합을 반환한다고 합니다.

 

논리 우선순위 문제

 

앞서 무한 반복 생성에서 봤듯이 python은 논리를 처리할 때 a == b in c이 있다고하면,

 

앞에서부터 연산을 하는게 아니라 a in c , b in c를 구한뒤 그 결과값이 a' , b' 이라고 하면 a'==b'을 진행하는 것 같다.

 

수학과 입장으로 참으로 마음에 안드는 결과가 아닐 수 없다.

 

객체 변환 문제

 

float과 int에 따른 논리 결과가 다른 문제를 보여준다.

 

본문에서 x<<y라는 operator가 있다.

 

이 operator는 비트가 y자리만큼 왼쪽으로 이동한 x를 반환한다는데 잘 모르겠다.

 

이것은 x에 2 ** y를 곱하는 것과 같은 결과라고 한다. 알고자 하는 결과와는 무관하니 넘어가자..

 

위와 같은 결과가 나오는 이유는

 

int와 float은 변환 과정에서 가까운 값으로 반올림하는 과정이 있다고 한다. 

 

int가 float 변환 과정에서 원래 값으로 변환이 된다고 하고,

 

float값에서 1을 더해줘서 원래 값이 나와야 하는데 뭐 반올림 과정에서 그대로 나타난다고 한다.

 

문제점을 알고 사용할수록 예기치 못한 에러를 이해하기 쉽다고 생각한다.

 

도움이 되기를 바란다. 

'python' 카테고리의 다른 글

코딩 스타일과 관리  (0) 2021.02.28
jupyter kernel 제대로 추가 안될 때  (2) 2021.01.24
python oracle DB 연동  (0) 2020.12.03
offline conda pack spyder설치 에러  (0) 2020.12.01
conda python 경로 인식못할 때  (0) 2020.11.28

가상환경1을 jupyter notebook의 커널로 추가하고 싶었는데 

 

커널이 생기긴한데 제대로 추가가 되지 않는 현상이 있었다.

 

python -m ipykernel install --user --name [가상환경명] --display-name [보이는 이름]

 

증상은 해당 명령어로 설치를 했는데도 해당 tensorflow 버전이 나오지 않았다.

 

한동안 커널을 안쓰다가 불편해서 이를 고치고자 설정을 뜯어 보았다.

 

jupyter가 깔린 가상환경을 편의상 가상환경0 이라고 하자.

 

가상환경1에서 python에 위치를 확인하기 위해 which python을 입력

 

나는 /root/anaconda3/envs/가상환경명/bin/python에 존재했다.

 

이제 jupyter kernelspec list로 커널 리스트를 확인

 

확인해보니 가상환경1( 제기준 tf1_14)이 목록에는 존재했다. 

vi /root/.local/share/[가상환경0]/kernels/[가상환경1]/kernel.json

에 들어가서 

 

argv부분에 python 경로가 적혀있을 것이다.

 

근데 python 경로가 [가상환경0]에 대한 경로로 설정되어 있었다.

 

/root/anaconda3/envs/추가할 가상환경명(가상환경1)/bin/python으로 수정

 

:wq!

저장

 

python -m ipykernel install --user --name [가상환경명1] --display-name [보이는 이름]

등록!

 

될줄 알았는데 안된다.

 

가상환경1에 kernel이 안깔려있어서 그렇다..

 

conda activate 가상환경1

 

conda install ipykernel

 

이제 jupyter들어가보면 잘 될 것이다.

'python' 카테고리의 다른 글

코딩 스타일과 관리  (0) 2021.02.28
python을 시작하기 전에  (0) 2021.02.27
python oracle DB 연동  (0) 2020.12.03
offline conda pack spyder설치 에러  (0) 2020.12.01
conda python 경로 인식못할 때  (0) 2020.11.28

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

확인