(83)

대형프로젝트 계획중

한가지 확실한 건 이건 진짜 개노가다가 맞음. 블로그를 좀 오래 전부터 보신 분들은 아시겠지만 깃헙에 유일하게 폴더로 분리된 대형 프로젝트가 두 개 있다. 첫번째가 프로젝트 제한효소, 두번째가 프로젝트 워드클라우드. 근데 이게 쌩코드가 올라와서 이걸 복사해서 수정해서 또 올려야되는데 귀찮아요... 그래서 Flask로 웹이랑 묶으려고 생각중이다. (프로젝트 제한효소는 DB로 쓰는 csv파일도 포함) 근데 또 고려할 게 생겼어...OTL 1) 코드 통합 문제 프로젝트 워드클라우드의 경우 한글/영어/Entrez 세 개의 코드가 있고, 프로젝트 제한효소에는 커터/파인더/서쳐 세 개의 코드가 있다. 프로젝트 제한효소는 세 코드가 사용 목적이 다 달라서 통합은 안되고, 한 페이지 안에서 세개를 다 띄우려면 아코디언..

input vs sys.stdin.readline()

예에에에에전에 백준 18108번 풀이를 올렸을 때 댓글로 질문이 하나 왔었다. input()대신 sys.stdin.realine()을 쓰는 이유를 알 수 있나요? 백준에서 빠르다고 해서 쓰고 있었음... 아니 농담 아니고 진짜다. 반복문 이런거 잘못 짜면 응애 나 애기시간초과! 가 반기는데 다른데서라도 시간 줄여야져... 일단 둘 다 입력 받을 때 쓰는 게 맞다. input() #input import sys sys.stdin.readline() #sys.stdin.readline() 각각 이렇게 쓰면 된다. 근데 이렇게만 해 두면 왜 쟤가 빠른지 체감이 잘 안 올 것이다. 우리가 input()을 쓸 때는 저렇게 쓰는 것 보단 input('메시지를 입력해주세요') 이런 식으로 쓴다. 이 때, 저 안에 있..

Python으로 JSON파일 읽기

JSON은 JavaScript Object Notation을 줄인 것으로, 보통 제이슨으로 읽는다. 일반적으로 클라이언트가 서버에서 가져오는 데이터는 이 형식이고, 현재 표준 형식으로 많이 쓰이고 있다. 원류는 자바스크립트지만 현재는 언어 독립적인 개별 포맷. 그러니까 누가 제이슨 파일 주세요 하면 JSON파일 달라는거지 제이슨씨 파일 주세요가 아니다 남의 파일을 왜 달라고 해 ​ 키-값 쌍으로 이루어진 데이터를 텍스트 형태로 기록해둔 것이라 휴먼 가독성은 좋다. 오늘의 도우미 { "Water": { "molecular weight": "18.016", "molecular formula": "H2O" }, "Ethanol": { "molecular weight": "46.07", "molecular fo..

재귀함수가 돌아가는 방식을 알아보자

재귀함수는 정의할 때 자기자신을 재참조한다고 했는데, 정의하는데 자기자신이 들어가면 대체 어떻게 돌아가는지 알아보자. 라이츄가 라이츄를 꺼내고 그 라이츄가 라이츄를 꺼내고 팩토리얼 def factorial(n): if n == 0: return 1 return n * factorial(n-1) 5!을 저걸로 계산하게 되면 1. factorial(5) = 5 * factorial(4) 2. factorial(4) = 4 * factorial(3) 3. factorial(3) = 3 * factorial(2) 4. factorial(2) = 2 * factorial(1) 5. factorial(1) = 1 * factorial(0) 6. factorial(0) = 1 7. 오케이 가릿 여기까지 왔더니 fac..

감마 함수+팩토리얼 코드에서 유리수 처리

아, 정확히는 정수가 아닌 유리수 말하는거다. 감마 함수? 일단 팩토리얼(n!)이 n부터 1까지 쫘라락 곱한다는것과 정수가 아닌 유리수는 그걸 감마 함수에 때려박아야 한다는 걸 대충 알고 계실 것이다. 감마함수는 팩토리얼의 상위호환으로, 대충 이런 식을 쓴다. 사실 식이 네 갠데 일반적으로 알려진 게 저 적분식인거고, 그나마 저 형태가 이해하기 쉽다. 나머지는 뭐 파이(원주율 말고 곱의 기호 파이) 뜨고 난리났음. 코드 from sympy import * from mpmath import mp import sys a = complex(sys.stdin.readline()) # 복소수는 complex로 입력해야 합니다. (int: 정수, float: 소수라고 생각하면 됨) t = symbols("t") e..

이중계승 추가

일단 이중계승이 뭐냐... 우리가 알고있는 팩토리얼은 n! = n*(n-1)*(n-2) 이런 식으로 곱하는거기때문에 종착점이 무조건 1이다. 근데 이중 계승은 곱하는 숫자의 공차가 2이기 때문에 입력한 숫자가 홀수냐 짝수냐에 따라 종착점이 갈린다. 홀수의 경우 종착점이 1이고, 짝수의 경우 종착점이 2가 된다. 그래서 6!!=6*4*2=48, 5!!=5*3*1=15가 된다. (그냥 계승은 6!이 720 5!이 120) import sys a = float(sys.stdin.readline()) factorial = 1 if a < 0: print("Can't calculate factorial") elif a == 0 or a == 1: print(factorial) # 0! = 1 elif a % 1 ..

팩토리얼 로직 또 수정

이건 또 언제 떠올랐냐면 밥 사러 편의점 가다가 떠오름... ㅋㅋㅋㅋㅋㅋㅋㅋ 아니 농담 아니고 진짜로 그래요 뜬금없이 샐러드 고르고 계산하다가 아 근데 자연수 아닌거 어캄? 이러고 떠오름 들어가기 전에... 팩토리얼이 되는 범위가 어디까지인가에 대해 설명을 좀 하자면... 팩토리얼(n!)은 n부터 1까지 쫙 곱하는 그게 맞는데, 0!은 0이 아니라 1이고(...) 음수에 대해서는 정의가 안 되어 있다. 그리고 정수가 아닌 유리수(즉 q/p꼴로 나타내는 수 중 p가 1이 아닌 것...아니 음수도 아냐 치워)에 대해서는 일반적으로 고등학교 과정에서 배우는 팩토리얼이 아니라 감마 함수를 써서 계산한다. 그러니까 저기다 때려박으면 된다. 수기로 하지 말고 알파신 부르자. (울프램알파도 저거 해준다) 감마(n)은..

팩토리얼 로직 수정+계승 소수

Factorial 로직 수정 재밌는 사실을 하나 알려주자면 출근길에 지하철에서 멍때리다 생각난거임... 6호선 생각보다 자리 없어요 여러분. 팩토리얼(n!) 그니까 계승이 1부터 n까지 쭉 곱하는거인 건 맞다. 맞는데 문제가 두 가지 있다. 첫째, 0! = 1이다. (0 아님) 둘째, 음수는 팩토리얼이 없다. (정수가 아닌 유리수는 감마함수 때려박으면 된다나...) 그래서 이 두 가지 케이스에 대한 처리를 해야 한다. import sys a = int(sys.stdin.readline()) # Factorial(계승): 일반적으로 n! = 1*2*3*...*n-1*n이다. (5!=1*2*3*4*5) factorial = 1 if a < 0: print("Can't calculate factorial") ..

순열조합

워드클라우드 py파일 만드는 김에 순열조합도 코딩했음. 순열: nPr(n개의 원소 중 r개를 중복 없이 늘어놓는 가짓수) 조합: nCr(n개의 원소 중 r개를 픽할 때의 가짓수) # permutation(순열): 서로 다른 n개의 원소 중 r개를 중복 없이 늘어놓는 것 def factorial(a): factorial = 1 for i in range(1,a+1): factorial = factorial * i return factorial # 순열에 팩토리얼이 들어가서 어쩔 수 없어요... # nPr(서로 다른 n개의 원소 중 r개를 중복 없이 늫어놓는 것)을 구하는 공식은 n!/(n-r)!입니다. n = int(input("n에 들어가는 수를 입력해주세요: ")) r = int(input("r에 들어..

워드클라우드 코드에 기능 추가

일단 Entrez랑 Text랑 추가된 기능이 조금 다름. 기본 맥락은 같습니다. 공통 기능 워드클라우드용 마스킹 이미지를 불러오기 위한 파일 창 추가 from argparse import FileType import tkinter from tkinter import filedialog 추가 소환한 모듈(...) root = tkinter.Tk() root.withdraw() dir_path = filedialog.askopenfilename(parent=root,initialdir="/home/koreanraichu",title='Please select a directory',filetypes = (("*.png","*png"),("*.jpg","*jpg"),("*.gif","*gif"))) image..

List comprehension

참고로 나도 오늘 처음 들은 개념이다. List comprehension-기본편 a = list(range(9)) print(a) 보통 리스트는 이런 식으로 생성하거나 a = [0,1,2,3,4,5,6,7,8] 이렇게 생성한다. (같은 리스트다) 이걸 리스트 컴프리헨션으로 생성하려면? a = list(i for i in range(9)) print(a) 이렇게 쓰거나 a = [i for i in range(100)] print(a) 쿨하게 대괄호 안에 끼워넣으면 된다. For문 넣기 참고로 본인 신조가 'For문 가는데 While이 국룰'이었는데 얘는 예외다. While이 들어가질 못함... for문과 달리 while은 조건부 반복문이라 그런 듯 하다. a = list(2 ** i for i in ran..

완전수 찾는 코드

이거 근데 우분투 놋북이 뭐가 불만인지 키보드가 안먹히데... 커널 올려줘도 난리여... 안그래도 오늘 진상 만나서 힘들었는데 너까지 왜그러냐... import sys a = int(sys.stdin.readline()) yaksu = [] for i in range(1,a+1): if a % i == 0: yaksu.append(i) yaksu_text = ''.join(str(yaksu)) print('{}의 약수는 {}입니다. '.format(a,yaksu_text)) if sum(yaksu) == 2 * a: print('{}는 자기 자신을 제외한 약수들의 합이 {}와 동일하므로 완전수입니다. '.format(a,a)) 전체 코드는 뜯어보고 자시고 할 것도 없음. 완전수는 자기 자신을 제외한 모든..

Project restriction enzyme: 패치노트

NEB Filter 추가 이제 NEB에서 파는 제한효소들만 볼 수 있습니다. (NEB: 뉴 잉글랜드 바이오랩스. NEB cutter 만든 거기 맞음) Cutter/Finder의 저장 형식 변경 일부 저장 형식이 변경되었습니다. 저장 디렉토리 출력 저장 시 현재 디렉토리를 출력해줍니다. FASTA파일 관련 문제 수정 1. FASTA 파일에 시퀀스가 소문자로 기록되어 있을 경우 제대로 못 찾던 문제를 수정했습니다. 2. FASTA 파일에 >가 여러개 일 경우 에러가 뜨는 대신 맨 위에 있는 >로 진행합니다. 참고로 왜 NEB냐면 거기껄 제일 많이 썼음. Genbank 파일 지원 문제가 하나 있는데 리드랑 파스랑 뭔 차인지 모르겠음. FASTA는 지에딧으로 열리는거라 보기라도 했지... Genbank는 gb파..

Cutter, Finder 공통 패치: FASTA 파일 불러오는 기능

패치노트 1. 꺾쇠(>)가 하나인 FASTA 파일 한정으로 읽어올 수 있습니다. (Biopython이 꺾쇠 개수에 따라 불러오는 방식이 다름) 2. FASTA 파일을 불러올 경우, 시퀀스 이름란에 FASTA file의 ID영역이 들어갑니다. (사실 description 넣으려다가 너무 길어서...) 3. FASTA 파일을 불러오는 데 성공할 경우에도 멘트가 출력됩니다. (실패할때는 당연히 출력됨) 개고생의 흔적 from argparse import FileType import tkinter from tkinter import filedialog from Bio import SeqIO # 정신사나워서 불러오는거랑 표 분리했습니다...OTL 이쪽이 모듈이다. (뭐가 많음) FASTA_open = input(..

Finder 기능추가: 정규식 도입

정말! 개 노가다끝에... 드디어 해냈음... 일단 도입하는 것 자체는 커터에서 했기때문에 크게 어려운 부분은 없었고, 문제가 좀 있었다. 1. 함수 정의하고 뺑뺑이를 돌렸는데 알파벳이 자꾸 하나만 바뀌는 문제(수정함) 2. 정규식은 찾아바꾸기가 안된다. (sub()은 토씨 하나 안 틀리고 바꿔주는거라 G..T로 찾고 G..T/로 바꾸면 모든 시퀀스가 죄다 G..T/로 바뀐다) 첫 번째 문제는 해결했고 두번째 문제의 경우 찾아바꾸기가 안돼서 정규식이 필요한 효소들은 어떻게 자르는지가 위에만 표시되어 있다. 살려줘요.

대형프로젝트 계획중

Coding/Python 2022. 8. 22. 01:09

한가지 확실한 건 이건 진짜 개노가다가 맞음. 


블로그를 좀 오래 전부터 보신 분들은 아시겠지만 깃헙에 유일하게 폴더로 분리된 대형 프로젝트가 두 개 있다. 첫번째가 프로젝트 제한효소, 두번째가 프로젝트 워드클라우드. 근데 이게 쌩코드가 올라와서 이걸 복사해서 수정해서 또 올려야되는데 귀찮아요... 그래서 Flask로 웹이랑 묶으려고 생각중이다. (프로젝트 제한효소는 DB로 쓰는 csv파일도 포함)

근데 또 고려할 게 생겼어...OTL 

1) 코드 통합 문제
프로젝트 워드클라우드의 경우 한글/영어/Entrez 세 개의 코드가 있고, 프로젝트 제한효소에는 커터/파인더/서쳐 세 개의 코드가 있다. 프로젝트 제한효소는 세 코드가 사용 목적이 다 달라서 통합은 안되고, 한 페이지 안에서 세개를 다 띄우려면 아코디언 패널이나 탭 메뉴가 있어야 한다. 워드클라우드도 Entrez는 입력 인자가 달라서 분리해야 하고, 한글과 영어는 언어에 따른 처리 인자만 달라서 코드를 통합하고 언어 선택을 라디오버튼으로 줄 수 있다. (페이지를 합칠거면 역시나 탭이나 아코디언 패널이 필요하다)

사실 이 부분은 별로 고민을 안한게 우리에겐 개쩌는 부트스트랩이 있다. 

2) 파일 브라우징 문제
내가 저걸 돌리는 OS가 리눅스라 이미지 브라우저나 글꼴 폴더를 다 고정해놓고 쓰고 있는데, 일단 이게 왜 문제냐면, 코드를 돌리는 OS가 리눅스라 저장 경로가 리눅스 위주이다. (윈도우는 홈이 없음) 리눅스는 글꼴도 저장해두는 폴더 가서 ttf나 otf 선택해서 쓰면 된다. 그럼 윈도우는요? 윈도우는 글꼴 어떻게 고르는지 모른다. 

프로젝트 제한효소도 FASTA, Genbank파일때문에 브라우저를 띄워야 하고, 워드클라우드는 마스킹 이미지때문에 브라우저를 띄워야 한다. OS 정보를 가져올 수 있으면 거기에 맞춰서 home이건 C드라이브건 띄우면 장땡. 저장은 브라우저 설정 따라가게 하면 된다. 

3) 입력 인자
여기서부터는 프로젝트 워드클라우드의 문제. (제한효소는 저 두개만 처리하면 일단 끝난다) 

Entrez는 Pubmed에서 논문 검색할 때 쓰는 검색어(A[TITLE] and B[TITLE])를 입력받기 때문에 그 부분에 대한 안내만 하면 된다. 문제는 그냥 워드클라우드인데, 이쪽은 현재 While True로 여러개 입력을 받고 있다. (하나만 써도 되긴 된다) IDE에서는 텍스트 편집이 어려워서 이렇게 했다. 

현재 가장 좋은 방법은 textarea를 크게 주고 하나만 입력받는 걸로 제한하는 것. While True 걸어놓고 거기에 대해 안내하는것보단 이게 나을 듯 하다. 샘플 텍스트로 한글 워드클라우드는 윤동주-별 헤는 밤을 제공할 예정. 그게 제일 이쁘게 나왔다. 

4) 글꼴
현재 워드클라우드 코드는 내가 보유한 글꼴을 선택해서 적용하고 있다. 그런데 다른 사람들이 내 글꼴을 쓸 수는 없고... 구글 웹폰트나 텍스트 에디터의 글꼴 선택 메뉴같은 게 있으면 좋을 것 같은데 그걸 어떻게 하는지를 몰라서, 이쪽으로는 더 알아봐야 할 듯 하다. 

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

input vs sys.stdin.readline()

Coding/Python 2022. 8. 22. 01:08

예에에에에전에 백준 18108번 풀이를 올렸을 때 댓글로 질문이 하나 왔었다. 

input()대신 sys.stdin.realine()을 쓰는 이유를 알 수 있나요?

백준에서 빠르다고 해서 쓰고 있었음... 아니 농담 아니고 진짜다. 반복문 이런거 잘못 짜면 응애 나 애기시간초과! 가 반기는데 다른데서라도 시간 줄여야져... 


일단 둘 다 입력 받을 때 쓰는 게 맞다. 

input()
#input

import sys
sys.stdin.readline()
#sys.stdin.readline()

각각 이렇게 쓰면 된다. 근데 이렇게만 해 두면 왜 쟤가 빠른지 체감이 잘 안 올 것이다. 

 

우리가 input()을 쓸 때는 저렇게 쓰는 것 보단 

input('메시지를 입력해주세요')

이런 식으로 쓴다. 이 때, 저 안에 있는 텍스트를 '프롬프트 메시지'라고 한다. 그럼 sys.stdin.readline()도 프롬프트 메시지가 있나요? 놉. 이게 sys.stdin.readline()이 input()보다 빠른 이유 중 하나다. 엥? 이유가 또 있어요? 예. 

파이썬에서는 입력을 받을 때 개행 문자(\n)가 같이 딸려온다. input()은 개행 문자를 떼버리는데 sys.stdin.readline()은 개행문자를 안 떼고 그냥 받는다. 그래서 sys.stdin.readline()으로 받고 나면 항상 rstrip()이나 strip() 메소드가 따라와야 한다. 

a = sys.stdin.readline().rstrip() 
a = sys.stdin.readline().strip()

그러니까 이렇게 써야 개행 문자를 떼고 입력을 받는다. 정확히 말하자면 rstrip()은 개행문자를 떼 주고, strip()은 공백을 떼버린다.

 

즉, sys.stdin.readline()이 빠른 이유는

1. 개행문자를 안 떼고

2. 프롬프트 메시지도 안 받기 때문

이라고 할 수 있다.

참고로 일부 IDE나 에디터에서 sys.stdin.readline()은 안먹으니 시간이 정말 급한거다 잘못하면 응애 나 애기시간초과! 가 반긴다 이런거 아님 걍 인풋 쓰자. 대표적인 예로 Jupyter에서는 sys.stdin.readline()이 입력을 안 받고(그냥 안받음) Spyder에서는 형변환 에러가 뜬다. 그냥 런던올림픽 펜싱심판 데려오면 안되나 아니 그냥 파이참을 써 파이참은 안해봤는데 VScode는 sys.stdin.readline()이 먹힌다.

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

Python으로 JSON파일 읽기

Coding/Python 2022. 8. 22. 01:06

JSON은 JavaScript Object Notation을 줄인 것으로, 보통 제이슨으로 읽는다. 일반적으로 클라이언트가 서버에서 가져오는 데이터는 이 형식이고, 현재 표준 형식으로 많이 쓰이고 있다. 원류는 자바스크립트지만 현재는 언어 독립적인 개별 포맷. 그러니까 누가 제이슨 파일 주세요 하면 JSON파일 달라는거지 제이슨씨 파일 주세요가 아니다 남의 파일을 왜 달라고 해

키-값 쌍으로 이루어진 데이터를 텍스트 형태로 기록해둔 것이라 휴먼 가독성은 좋다.


오늘의 도우미

{
	"Water": {
		"molecular weight": "18.016",
		"molecular formula": "H2O"
	},
	"Ethanol": {
		"molecular weight": "46.07",
		"molecular formula": "C2H5OH"
	},
	"Glucose": {
		"molecular weight": "180.156",
		"molecular formula": "C6H12O6"
	},
	"Sucrose": {
		"molecular weight": "342.3",
		"molecular formula": "C12H22O11"
	}
}

짜잔 이래뵈도 수제다 

그리고 이거 하려면 모듈 불러야 한다. 별도로 설치는 안해도 되고 

import json

이거 한줄만 추가합시다. 

 

JSON파일 읽기

with open('/home/koreanraichu/test.json') as f:
    json_data = json.load(f)
print(json.dumps(json_data))

그냥 이렇게 쓰면 알아서 불러온다. 

 

{"Water": {"molecular weight": "18.016", "molecular formula": "H2O"}, "Ethanol": {"molecular weight": "46.07", "molecular formula": "C2H5OH"}, "Glucose": {"molecular weight": "180.156", "molecular formula": "C6H12O6"}, "Sucrose": {"molecular weight": "342.3", "molecular formula": "C12H22O11"}}

형식에서 그렇게 큰 기대는 하지 말자. (참고로 VScode가 가끔 키보드 먹통이 되는 문제가 있어서 spyder로 함...)

그럼 저기서 특정 데이터만 볼 수 있어요? 예, 됩니다. 

{"Water": {"molecular weight": "18.016", "molecular formula": "H2O"}

형식이 잘 보면 딕셔너리다. 파이썬은 JSON파일을 불러올 때 딕셔너리로 불러오는데, 이 파일의 경우 다중 딕셔너리(2중)이다. 그리고 딕셔너리는 뭐다? 키-밸류로 되어 있고 키값으로 픽이 된다 그죠? 

 

print(json_data['Water'])
print(json_data['Water']['molecular formula'])

걍 이렇게 부르면 된다. 정렬도 가능하다. 

 

JSON파일 수정하기

{"Water": {"molecular weight": "18.016", "molecular formula": "H2O"}, "Ethanol": {"molecular weight": "46.07", "molecular formula": "C2H5OH"}, "Glucose": {"molecular weight": "180.156", "molecular formula": "C6H12O6"}, "Sucrose": {"molecular weight": "342.3", "molecular formula": "C12H22O11"}, "Methanol": {"molecular weight": "", "molecular formula": ""}}

여기에 메탄올에 대한 정보를 새로 추가했는데, 문제가 하나 있다. 

"Methanol": {"molecular weight": "", "molecular formula": ""}

뭐야 메탄올 정보 어디갔어요? 

이거 그럼 raw file 수정해야 하나요? ㄴㄴ 파이썬에서 커버칠 수 있다. 

json_data['Methanol']['molecular weight'] = '32.04'
json_data['Methanol']['molecular formula'] = 'CH3OH'

이런 식으로 키값을 픽해서 밸류를 수정하고 

with open ('/home/koreanraichu/test.json','w', encoding='utf-8') as s:
    json.dump(json_data,s)

이렇게 하면 들여쓰기가 가출한다. 

 

with open ('/home/koreanraichu/test.json','w', encoding='utf-8') as s:
    json.dump(json_data,s,indent = '\t')

indent = \t를 주자. 

 

JSON파일 쓰기

JSON파일을 읽고 수정해봤으면 이제 쓸 시간이다. 아니 거기 에디터 꺼요... 

 

cellphone = dict()
cellphone['Samsung'] = "Galaxy Z flip"
cellphone['Apple'] = "iPhone"
tabletpc = dict()
tabletpc['Samsung'] = 'Galaxy tab'
tabletpc['Apple'] = 'iPad'

핸드폰과 태블릿PC에 대한 딕셔너리를 생성해준다. (핸드폰 영어로 cellphone임)

 

mobile_device = dict()
mobile_device['Cellphone'] = cellphone
mobile_device['Tablet PC'] = tabletpc

그리고 두 개의 딕셔너리를 밸류로 갖는 큰 딕셔너리(모바일 기기)를 하나 만든다. 

 

with open ('/home/koreanraichu/test2.json','w', encoding='utf-8') as s:
    json.dump(mobile_device,s,indent = '\t')

그리고 묶은 딕셔너리를 그대로 JSON파일로 쓰면 이렇게 된다. 참 쉽죠? 

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

재귀함수가 돌아가는 방식을 알아보자

Coding/Python 2022. 8. 22. 01:02

재귀함수는 정의할 때 자기자신을 재참조한다고 했는데, 정의하는데 자기자신이 들어가면 대체 어떻게 돌아가는지 알아보자. 라이츄가 라이츄를 꺼내고 그 라이츄가 라이츄를 꺼내고 


팩토리얼

def factorial(n):
  if n == 0:
    return 1
  return n * factorial(n-1)

5!을 저걸로 계산하게 되면 

1. factorial(5) = 5 * factorial(4)
2. factorial(4) = 4 * factorial(3)
3. factorial(3) = 3 * factorial(2)
4. factorial(2) = 2 * factorial(1)
5. factorial(1) = 1 * factorial(0)
6. factorial(0) = 1
7. 오케이 가릿

여기까지 왔더니 factorial(0)이 1이네? 그럼 호출 중단하고 싹 다 곱하면 된다. 이중계승의 경우 홀수와 짝수의 종착점이 다르기때문에 n이 0일때와 1일때 둘 다 정의해줘야 한다. 

 

피보나치 수열

def fibonacci(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fibonacci(n-2) + fibonacci(n-1)

 

코드 돌아가는거 보여주는걸로 돌렸더니 74단계 걸린거 실화다. 

1. 피보나치(5) = 피보나치(4) + 피보나치(3)
2. 피보나치(3) = 피보나치(2) + 피보나치(1)
3. 피보나치(1) = 1
4. 피보나치(2) = 피보나치(1) + 피보나치(0)
5. 피보나치(0) = 0
6. 오케이 가릿 

대충 이런 느낌이다. 재귀가 끝나는 조건문을 만날때까지는 계속 함수를 호출하고, 재귀가 끝나면 싹 계산하는 방식. 

'Coding > Python' 카테고리의 다른 글

input vs sys.stdin.readline()  (0) 2022.08.22
Python으로 JSON파일 읽기  (0) 2022.08.22
감마 함수+팩토리얼 코드에서 유리수 처리  (0) 2022.08.22
이중계승 추가  (0) 2022.08.22
팩토리얼 로직 또 수정  (0) 2022.08.22
Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

감마 함수+팩토리얼 코드에서 유리수 처리

Coding/Python 2022. 8. 22. 00:59

아, 정확히는 정수가 아닌 유리수 말하는거다. 


감마 함수? 

일단 팩토리얼(n!)이 n부터 1까지 쫘라락 곱한다는것과 정수가 아닌 유리수는 그걸 감마 함수에 때려박아야 한다는 걸 대충 알고 계실 것이다. 감마함수는 팩토리얼의 상위호환으로, 

대충 이런 식을 쓴다. 사실 식이 네 갠데 일반적으로 알려진 게 저 적분식인거고, 그나마 저 형태가 이해하기 쉽다. 나머지는 뭐 파이(원주율 말고 곱의 기호 파이) 뜨고 난리났음. 

 

코드

from sympy import *
from mpmath import mp
import sys
a = complex(sys.stdin.readline())
# 복소수는 complex로 입력해야 합니다. (int: 정수, float: 소수라고 생각하면 됨)
t = symbols("t")
expr = t ** (a - 1) * exp(-t)
try: 
    print(Integral((expr),(t,0,oo)).doit())
except: 
    print("Cannot calculate Gamma function")

일단 어제 심파이랑 mpmath 올리고 해 본 결과 expr에 저 식 때려박고 음수로 입력하면 에러가 뜬다. 즉, 예외처리가 가능하다. 근데 예외 처리에는 문제가 몇 개 있는데 

1) 원래 감마 함수는 0에서도 정의가 안 된다. (정의역이 0보다 크다) 
2) 그리고 try except는 if랑 같이 못 쓴다. 

대충 이런 문제가 있다. 

 

from sympy import *
from mpmath import mp
import sys
a = complex(sys.stdin.readline())
# 복소수는 complex로 입력해야 합니다. (int: 정수, float: 소수라고 생각하면 됨)
t = symbols("t")
expr = t ** (a - 1) * exp(-t)
gamma_function = integrate((expr),(t,0,oo))
if a.real > 0:
    if gamma_function % 1 == 0:
        print(round(gamma_function))
    else: 
        print(round(gamma_function,3))
else: 
    print("Cannot calculate Gamma function")

그래서 0도 계산 못 하는걸로 처리하느라 if 줬다. 

참고로 복소수의 경우 실수부가 음수여도 알파신 때려박으면 계산은 해 준다. 결과가 복소수긴 한데... 근데 왜 저기서는 실수부가 양수일 때만 처리했느냐... Sympy는 복소수 실수부가 음수일 때 적분 객체만 띡 생성하고 끝난다. 

 

팩토리얼 코드 수정

def gamma_function(a):
    t = symbols("t")
    expr = t ** (a - 1) * exp(-t)
    if a.real > 0:
        return integrate((expr),(t,0,oo))
    else: 
        return False

함수 자체는 어렵지 않은데, 문제가 하나 있다면 감마함수는 

이다. 그래서 저기에 1.5를 넣고 저 함수 그대로 돌리면 0.5!을 계산해준다. 

 

elif a % 1 != 0:
    print(round(gamma_function(a+1),3))

그래서 계산할 때 1을 더해줘야 한다. (1.5!을 구할거면 2.5를 넣어야 한다) 복소수도 마찬가지로 실수부에 1을 더해야 하지만 저 코드에서는 복소수 지원 안 한다. 


from sympy import *
from mpmath import mp
import sys

def gamma_function(a):
    t = symbols("t")
    expr = t ** (a - 1) * exp(-t)
    if a.real > 0:
        return integrate((expr),(t,0,oo))
    else: 
        return False

a = float(sys.stdin.readline().strip())
# Factorial(계승): 일반적으로 n! = 1*2*3*...*n-1*n이다. (5!=1*2*3*4*5)
factorial = 1
if a < 0:
    print("Can't calculate factorial")
    # 음수는 factorlal이 없음
elif a == 0:
    print(factorial)
    # 0! = 1
elif a % 1 != 0:
    print(round(gamma_function(a+1),3))
else:
    for i in range(int(a),0,-1):
        factorial *= i
    print(factorial)

For

 

from sympy import *
from mpmath import mp
import sys

def gamma_function(a):
    t = symbols("t")
    expr = t ** (a - 1) * exp(-t)
    if a.real > 0:
        return integrate((expr),(t,0,oo))
    else: 
        return False

a = float(sys.stdin.readline().strip())
# 와 팩토리얼이 생각보다 빡센거였구나... 
# Factorial(계승): 일반적으로 n! = 1*2*3*...*n-1*n이다. (5!=1*2*3*4*5)
factorial = 1
if a < 0: 
    print("Can't calculate factorial")
    # 음수는 factorial이 없음
elif a == 0: 
    factorial = 1
    # 0! = 1
elif a % 1 != 0:
    print(round(gamma_function(a+1),3))
else: 
    while a >= 1:
        factorial *= a
        a -= 1
    print(factorial)

While

'Coding > Python' 카테고리의 다른 글

Python으로 JSON파일 읽기  (0) 2022.08.22
재귀함수가 돌아가는 방식을 알아보자  (0) 2022.08.22
이중계승 추가  (0) 2022.08.22
팩토리얼 로직 또 수정  (0) 2022.08.22
팩토리얼 로직 수정+계승 소수  (0) 2022.08.22
Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

이중계승 추가

Coding/Python 2022. 8. 22. 00:56

일단 이중계승이 뭐냐... 

우리가 알고있는 팩토리얼은 n! = n*(n-1)*(n-2) 이런 식으로 곱하는거기때문에 종착점이 무조건 1이다. 근데 이중 계승은 곱하는 숫자의 공차가 2이기 때문에 입력한 숫자가 홀수냐 짝수냐에 따라 종착점이 갈린다. 홀수의 경우 종착점이 1이고, 짝수의 경우 종착점이 2가 된다. 그래서 6!!=6*4*2=48, 5!!=5*3*1=15가 된다. (그냥 계승은 6!이 720 5!이 120)


import sys
a = float(sys.stdin.readline())
factorial = 1
if a < 0:
    print("Can't calculate factorial")
elif a == 0 or a == 1:
    print(factorial)
    # 0! = 1
elif a % 1 != 0:
    print("정수가 아닌 유리수는 일반적인 방법으로 팩토리얼을 구할 수 없습니다. ")
else:
    for i in range(int(a),0,-2):
        factorial *= i
    print(factorial)

for

 

import sys
a = float(sys.stdin.readline())
factorial = 1
if a < 0:
    print("Can't calculate factorial")
elif a == 0 or a == 1:
    print(factorial)
    # 0! = 1
elif a % 1 != 0:
    print("정수가 아닌 유리수는 일반적인 방법으로 팩토리얼을 구할 수 없습니다. ")
else:
    while a > 0:
        factorial *= a
        a -= 2
    print(factorial)

while

근데 저거때문에 뭐가 별도로 추가되는 건 아니라 걍 2씩 빼고 곱하게 해놨음. 참고로 0이랑 1은 내가 직접 울프럼알파에서 돌려봤다. (감마함수도 몇개 돌려보긴 했는데 갸는 적분이라 코딩 못함... 일단 식 자체를 내가 이해를 못했어요)

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

팩토리얼 로직 또 수정

Coding/Python 2022. 8. 22. 00:55

이건 또 언제 떠올랐냐면 밥 사러 편의점 가다가 떠오름... ㅋㅋㅋㅋㅋㅋㅋㅋ 

아니 농담 아니고 진짜로 그래요 뜬금없이 샐러드 고르고 계산하다가 아 근데 자연수 아닌거 어캄? 이러고 떠오름 


들어가기 전에... 팩토리얼이 되는 범위가 어디까지인가에 대해 설명을 좀 하자면... 팩토리얼(n!)은 n부터 1까지 쫙 곱하는 그게 맞는데, 0!은 0이 아니라 1이고(...) 음수에 대해서는 정의가 안 되어 있다. 그리고 정수가 아닌 유리수(즉 q/p꼴로 나타내는 수 중 p가 1이 아닌 것...아니 음수도 아냐 치워)에 대해서는 일반적으로 고등학교 과정에서 배우는 팩토리얼이 아니라 감마 함수를 써서 계산한다. 그러니까

저기다 때려박으면 된다. 수기로 하지 말고 알파신 부르자. (울프램알파도 저거 해준다) 

감마(n)은 (n-1)!, 즉 감마(3) 하면 2!이고 감마(4) 하면 3!이다. 
그리고 저기에 소수를 넣으면... 어...... 나 루트 파이 본 거 같음... 
복소수? 된다. 허수부가 0이 아니어도 되는데 실수부는 0보다 커야 한다. 

아무튼 저기다 때려박으려면 일단 0보다 커야 한다. 0보다 작으면 감마함수 할아버지가 와도 답이 없다. 아무튼, 그래서 일차적으로 음수가 들어가면 팩토리얼이 없다고 나오는것. 그럼 이번에는 뭐때문에 수정했냐고? 아니 정수가 아닌 유리수 처리때문에 했다니까요. 저건 코딩 못해... 


For문

import sys
a = float(sys.stdin.readline())
# Factorial(계승): 일반적으로 n! = 1*2*3*...*n-1*n이다. (5!=1*2*3*4*5)
factorial = 1
if a < 0:
    print("Can't calculate factorial")
    # 음수는 factorlal이 없음
elif a == 0:
    print(factorial)
    # 0! = 1
elif a % 1 != 0:
    print("정수가 아닌 유리수는 일반적인 방법으로 팩토리얼을 구할 수 없습니다. ")
else:
    for i in range(int(a),0,-1):
        factorial *= i
    print(factorial)

기본적인 로직은 비슷하고 밑에 정수가 아닌 유리수를 판별하는 코드가 추가되었다. 정확히는 0보다 크면서 정수가 아닌 유리수(음수는 위에서 거른다). 저것도 밥 먹다가 0.5 이런건 1보다 작은거니까 1로 나누면 나머지가 나오겠지? 해서 시험삼아 해 보고 오케이 가릿 한 거. 회사에서 점심먹다 한 거라 노션에 올린 코드도 수기로 적은 거다. 날코딩에 이은 손코딩인가 

참고로 입력이 float로 받는거라 for문 돌릴 때는 int로 형변환 한번 해 줘야 한다. 안그러면 에러난다. 

 

While문

import sys
a = float(sys.stdin.readline())
# 와 팩토리얼이 생각보다 빡센거였구나... 
# Factorial(계승): 일반적으로 n! = 1*2*3*...*n-1*n이다. (5!=1*2*3*4*5)
factorial = 1
if a < 0: 
    print("Can't calculate factorial")
    # 음수는 factorial이 없음
elif a == 0: 
    factorial = 1
    # 0! = 1
elif a % 1 != 0:
    print("정수가 아닌 유리수는 일반적인 방법으로 팩토리얼을 구할 수 없습니다. ")
else: 
    while a >= 1:
        factorial *= a
        a -= 1
    print(factorial)

While은 for문과 달리 조건부 반복문이라 팩토리얼을 구하는 로직 자체가 달라서, a가 양수(자연수)이면 factorial이라는 변수에 a를 곱하고 a에 1을 빼는 걸 a가 1이 될 때까지(그래서 조건에 a >= 1이라고 되어 있다) 하면 된다. 그래서 따로 형변환을 할 필요가 없다. 

대신 저대로 출력하면 소수점이 붙어서 나오니까 그거 뵈기 싫으면 출력문에서 형변환 하면 된다. 

 

함수 이식판

def factorial(a):
    factorial = 1
    if a < 0:
        return False
    elif a == 0:
        factorial = 1
        return factorial
    elif a % 1 != 0:
        return False
    else:
        for i in range(int(a),0,-1):
            factorial *= i
        return factorial
# Factorial 구하는 로직(...)

어째서인지는 모르겠으나 함수와 클래스(얘도 근데 안에 함수 들었잖음...)에는 print 말고 return이 국룰이다. print는 화면에 출력하라는 얘기이고 return은 반환하라는 얘기. 즉 함수 다 돌리고 결과 반환하라는 얘기다. 덕분에 for나 while보다는 짜기가 편해진게 팩토리얼이 정의가 안 되는 케이스면 걍 return false 때려버리면 돼서 편하다. 

해당 함수는 순열/조합/계승소수 코드에 삽입되어 있다. 

'Coding > Python' 카테고리의 다른 글

감마 함수+팩토리얼 코드에서 유리수 처리  (0) 2022.08.22
이중계승 추가  (0) 2022.08.22
팩토리얼 로직 수정+계승 소수  (0) 2022.08.22
순열조합  (0) 2022.08.22
워드클라우드 코드에 기능 추가  (0) 2022.08.22
Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

팩토리얼 로직 수정+계승 소수

Coding/Python 2022. 8. 22. 00:53

Factorial 로직 수정

재밌는 사실을 하나 알려주자면 출근길에 지하철에서 멍때리다 생각난거임... 6호선 생각보다 자리 없어요 여러분. 

팩토리얼(n!) 그니까 계승이 1부터 n까지 쭉 곱하는거인 건 맞다. 맞는데 문제가 두 가지 있다. 
첫째, 0! = 1이다. (0 아님)
둘째, 음수는 팩토리얼이 없다. (정수가 아닌 유리수는 감마함수 때려박으면 된다나...)

그래서 이 두 가지 케이스에 대한 처리를 해야 한다. 

 

import sys
a = int(sys.stdin.readline())
# Factorial(계승): 일반적으로 n! = 1*2*3*...*n-1*n이다. (5!=1*2*3*4*5)
factorial = 1
if a < 0:
    print("Can't calculate factorial")
    # 음수는 factorlal이 없음
elif a == 0:
    print(factorial)
    # 0! = 1
else:
    for i in range(a,0,-1):
        factorial *= i
    print(factorial)

for

 

import sys
a = int(sys.stdin.readline())
# 와 팩토리얼이 생각보다 빡센거였구나... 
# Factorial(계승): 일반적으로 n! = 1*2*3*...*n-1*n이다. (5!=1*2*3*4*5)
factorial = 1
if a < 0: 
    print("Can't calculate factorial")
    # 음수는 factorial이 없음
elif a == 0: 
    factorial = 1
    # 0! = 1
else: 
    while a >= 1:
        factorial *= a
        a -= 1
    print(factorial)

while

 

def factorial(a):
    factorial = 1
    if a < 0:
        return False
    elif a == 0:
        factorial = 1
        return factorial
    else:
        for i in range(a,0,-1):
            factorial *= i
        return

순열/조합에 함수로 이식된 형태

 

계승 소수

이건 뭐냐면 n! - 1이나 n! + 1이 소수인 걸 말한다. 끝. (대충 펀쿨섹좌 짤) 와 이걸 이렇게 

 

import sys
a = int(sys.stdin.readline())
# 역사와 전통의 그거 맞음

def factorial(a):
    factorial = 1
    if a < 0:
        return False
    elif a == 0:
        factorial = 1
        return factorial
    else:
        for i in range(a,0,-1):
            factorial *= i
        return factorial
# Factorial 구하는 로직(...)

def isprime(a):
    sqrt = int(a ** 0.5)
    if a < 2:
        return False
    for i in range(2,sqrt+1):
        if a % i == 0:
            return False
    else: 
        return True
# 소수 정의 함수

plus_factorial = factorial(a) + 1
minus_factorial = factorial(a) - 1

if isprime(minus_factorial) and isprime(plus_factorial):
    print("{}! - 1, {}! + 1 둘 다 {}, {}로 계승 소수입니다. ".format(a,a,minus_factorial,plus_factorial))
elif isprime(minus_factorial):
    print("{}! - 1이 {}로 계승 소수입니다. ".format(a,minus_factorial))
elif isprime(plus_factorial):
    print("{}! + 1이 {}로 계승 소수입니다. ".format(a,plus_factorial))
else:
    print("{}! - 1, {}! + 1 둘 다 {}, {}로 계승 소수가 아닙니다. ".format(a,a,minus_factorial,plus_factorial))

이게 전체 코드다. 코드 자체는 크게 입력/함수/계산/판별로 나뉜다. 

참고로 본인 원래 모듈이랑 함수정의 다 맨 위에서 해버리는 스타일임. 제한효소때도 그래서 class가 위로 갔었다. 

 

def factorial(a):
    factorial = 1
    if a < 0:
        return False
    elif a == 0:
        factorial = 1
        return factorial
    else:
        for i in range(a,0,-1):
            factorial *= i
        return factorial
# Factorial 구하는 로직(...)

def isprime(a):
    sqrt = int(a ** 0.5)
    if a < 2:
        return False
    for i in range(2,sqrt+1):
        if a % i == 0:
            return False
    else: 
        return True
# 소수 정의 함수

함수는 팩토리얼이랑 소수 판별 두 개가 들어가 있다. 

 

if isprime(minus_factorial) and isprime(plus_factorial):
    print("{}! - 1, {}! + 1 둘 다 {}, {}로 계승 소수입니다. ".format(a,a,minus_factorial,plus_factorial))
elif isprime(minus_factorial):
    print("{}! - 1이 {}로 계승 소수입니다. ".format(a,minus_factorial))
elif isprime(plus_factorial):
    print("{}! + 1이 {}로 계승 소수입니다. ".format(a,plus_factorial))
else:
    print("{}! - 1, {}! + 1 둘 다 {}, {}로 계승 소수가 아닙니다. ".format(a,a,minus_factorial,plus_factorial))

이쪽이 판별 부분. 위키피디아에 예시로 나온 것 중에 n! - 1이랑 n! + 1 둘 다 소수인 게 있는데 3이 그 예이다. (6 - 1은 5고 6 + 1은 7)

'Coding > Python' 카테고리의 다른 글

이중계승 추가  (0) 2022.08.22
팩토리얼 로직 또 수정  (0) 2022.08.22
순열조합  (0) 2022.08.22
워드클라우드 코드에 기능 추가  (0) 2022.08.22
List comprehension  (0) 2022.08.22
Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

순열조합

Coding/Python 2022. 8. 22. 00:50

워드클라우드 py파일 만드는 김에 순열조합도 코딩했음. 

순열: nPr(n개의 원소 중 r개를 중복 없이 늘어놓는 가짓수)
조합: nCr(n개의 원소 중 r개를 픽할 때의 가짓수)


# permutation(순열): 서로 다른 n개의 원소 중 r개를 중복 없이 늘어놓는 것
def factorial(a):
    factorial = 1
    for i in range(1,a+1):
        factorial = factorial * i
    return factorial
# 순열에 팩토리얼이 들어가서 어쩔 수 없어요... 
# nPr(서로 다른 n개의 원소 중 r개를 중복 없이 늫어놓는 것)을 구하는 공식은 n!/(n-r)!입니다. 
n = int(input("n에 들어가는 수를 입력해주세요: "))
r = int(input("r에 들어가는 수를 입력해주세요: "))
P = factorial(n) / factorial(n - r)
print("{}개의 원소 중 {}개를 중복 없이 늘어놓을 수 있는 가짓수의 계산 결과는 {}입니다. ".format(n,r,int(P)))

이게 순열이고 

 

# n개의 원소 중 r개를 택하는 것이 조합입니다. nCr로 표기합니다. 
def factorial(a):
    factorial = 1
    for i in range(1,a+1):
        factorial = factorial * i
    return factorial
# 아 얘는 조합 구하는데 순열이 필요해서 어쩔 수 없음. 
# nCr을 구하는 공식은 n!/r!(n-r)!입니다. 
n = int(input("n에 들어가는 수를 입력해주세요: "))
r = int(input("r에 들어가는 수를 입력해주세요: "))
bunmo = factorial(r) * factorial(n - r)
C = factorial(n)/bunmo
print(C)

이게 조합임다. 

'Coding > Python' 카테고리의 다른 글

팩토리얼 로직 또 수정  (0) 2022.08.22
팩토리얼 로직 수정+계승 소수  (0) 2022.08.22
워드클라우드 코드에 기능 추가  (0) 2022.08.22
List comprehension  (0) 2022.08.22
완전수 찾는 코드  (0) 2022.08.22
Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

워드클라우드 코드에 기능 추가

Coding/Python 2022. 8. 22. 00:46

일단 Entrez랑 Text랑 추가된 기능이 조금 다름. 기본 맥락은 같습니다. 


공통 기능

워드클라우드용 마스킹 이미지를 불러오기 위한 파일 창 추가

 

from argparse import FileType
import tkinter
from tkinter import filedialog

추가 소환한 모듈(...)

 

root = tkinter.Tk()
root.withdraw()
dir_path = filedialog.askopenfilename(parent=root,initialdir="/home/koreanraichu",title='Please select a directory',filetypes = (("*.png","*png"),("*.jpg","*jpg"),("*.gif","*gif")))
image = np.array(Image.open(dir_path)) 
# 마스킹할 이미지(흰 바탕에 검정색을 권장함)
font_path = '/usr/share/fonts/나눔손글씨 바른히피.ttf'
wordcloud = WordCloud(font_path = font_path,stopwords=STOPWORDS,
                      background_color="#ffffff",colormap="magma",width = 800, height=800,
                      mask=image)
# Font path: 글꼴 설정하실 경우 여기에 쓰세요
# background color: wordcloud 배경 설정할 때 여기서 하세요 
# colormap: 워드클라우드 글자색을 여기서 바꿔주세요(matplotlib colormap 치면 많이 나옵니다)

글꼴은 고정된 상태이다. 

 

분기

공통적으로 워드클라우드를 저장하는 건 똑같은데, Text랑 Entrez랑 조금 다른 부분이 있다. 일단 텍스트부터 보고 가자. 

 

root = tkinter.Tk()
root.withdraw()
save_path = filedialog.asksaveasfilename(parent=root,initialdir="/home/koreanraichu",title='Please select a directory',filetypes = (("*.png","*png"),("*.jpg","*jpg"),("*.gif","*gif")))
image = np.array(Image.open(dir_path)) 
wordcloud = wordcloud.generate_from_text(text)
plot.figure(figsize=(15,15))
plot.axis('off')
plot.imshow(wordcloud)
plot.savefig(save_path)
plot.show()
print("wordcloud saved where {}".format(save_path))

이쪽이 Text에 적용된 코드. 파일명도 저기서 입력하면 된다. 

 

term = input("Entrez database에서 가져오고 싶은 주제가 뭔가요? (Title로 검색) \n")
year = input("특별히 보고 싶은 년도가 있나요? (optional, 없으면 공백으로 입력해주세요) \n")
if year: 
    terms = "{}[TITLE] AND {}[YEAR]".format(term,year)
else: 
    terms = "{}[TITLE]".format(term)

Entrez의 경우 일단 용어(그니까 논문 제목) 혹은 연도를 입력받되, 연도가 optional이다. 여기는 차후 저자 검색 등의 조건이 추가되면 elif 늘어나서 괴랄해 질 예정... 사실 핸들에 있는 걸 가져올 수 있으면 좋은데, 그게 사실상 불가능하다. 아마 나중에 검색어가 늘어나면 입력을 []까지 해서 받거나 코드단에서 수정하고 text처럼 될 지도 모름... 

 

if year:
    save_dir = "{}/{}&{}.png".format(save_path,term,year)
else: 
    save_dir = "{}/{}.png".format(save_path,term)

저장 경로가 뜨는 기본 골자는 같지만, 위에서 연도와 용어를 입력받기 때문에 파일명이 그걸로 자동 생성된다. 즉, 파일 이름을 입력하는 게 아니라 말 그대로 저장 경로만 선택해주면 된다. 


입력 관련 추가 수정사항

검색어 입력할 때 단어[조건] AND 단어[조건] 이런 식으로 통으로 입력해야 함. 대신 그걸로 파일명 만들어드립니다. 

예: Bacteria[TITLE] AND 2022[YEAR]

 

import re

일단 규식이형부터 불러봅니다

terms = terms.replace('[','-')
terms = terms.replace(']','-')
# 이스케이프 시퀀스 멕여도 안돼서 결국 이게 최선이었음... 
escape_terms = re.findall('-.{0,5}-',terms)
for i in escape_terms:
    terms = terms.replace(i,"")

일단 대괄호가 메타문자기때문에 저게 낑겨있으면 인식을 못해요 
근데 더 골때리는건 이스케이프 뭐시기 처리를 했는데도 불구하고 인식을 못해 
그래서 제한효소 DB때처럼 걍 대괄호를 다 하이픈으로 바꾸고 정규식으로 찾은 다음 빼버림 

그러니까 중간과정이 


Bacteria[TITLE] AND 2022[YEAR]
Bacteria-TITLE- AND 2022-YEAR-
Bacteria AND 2022

이렇게 되는거임. 

 

wordcloud saved where /home/koreanraichu/2022 AND bacteria.png.png

멘트 수정해야겠구만. 

+추가 기능: 그래프 여백 제거


일부 코드의 함수화

def replace_function (a):
    a = a.replace('[','-')
    a = a.replace(']','-')
    escape_terms = re.findall('-.{0,5}-',a)
    for i in escape_terms:
        a = a.replace(i,"")
    if '/' in a:
        a = a.replace('/','-')
    return a
# term 변환하는 거 함수로 뺐습니다. 근데 블록 실행하기 더 귀찮아진 건 기분탓인가... ㅡㅡ

엔트레즈: 입력받은 검색어 파일명으로 바꾸는 코드

 

def munjang_to_noun (a):
    a = ' '.join(a)
    a = okt.nouns(a)
    a = ' '.join(a)
    return a

한글: 텍스트 한글 처리하는 코드(저거 okt 돌리고 다시 join 안하면 작은따옴표 붙어서 나옴)

'Coding > Python' 카테고리의 다른 글

팩토리얼 로직 수정+계승 소수  (0) 2022.08.22
순열조합  (0) 2022.08.22
List comprehension  (0) 2022.08.22
완전수 찾는 코드  (0) 2022.08.22
Project restriction enzyme: 패치노트  (0) 2022.08.22
Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

List comprehension

Coding/Python 2022. 8. 22. 00:43

참고로 나도 오늘 처음 들은 개념이다. 


List comprehension-기본편

a = list(range(9))
print(a)

보통 리스트는 이런 식으로 생성하거나 

a = [0,1,2,3,4,5,6,7,8]

이렇게 생성한다. (같은 리스트다) 

이걸 리스트 컴프리헨션으로 생성하려면? 

a = list(i for i in range(9))
print(a)

이렇게 쓰거나

a = [i for i in range(100)]
print(a)

쿨하게 대괄호 안에 끼워넣으면 된다. 

 

For문 넣기

참고로 본인 신조가 'For문 가는데 While이 국룰'이었는데 얘는 예외다. While이 들어가질 못함... for문과 달리 while은 조건부 반복문이라 그런 듯 하다. 

 

a = list(2 ** i for i in range(9))
print(a)
[1, 2, 4, 8, 16, 32, 64, 128, 256]

걍 이렇게 쓰세여. 

a = list(i ** 2 for i in range(9))
print(a)
[0, 1, 4, 9, 16, 25, 36, 49, 64]

자매품(2제곱)

 

if문 넣기

def isprime(a):
    sqrt = int(a ** 0.5)
    if a == 1: 
        return False
    for i in range(2,sqrt+1):
        if a % i == 0:
            return False
    else: 
        return True

솔직히 홀짝은 너무 진부해서 가져와봤음. 이건 백준 함수파트 풀 때 개근했던 소수 찾는 함수다. 

 

a = [i for i in range(100) if isprime(i)]
print(a)
[0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

일단... 저 함수 자체를 좀 손봐야 하는 게, 백준 소수파트는 숫자가 작아봐야 1이다. 그래서 1보다 작은 수가 아니라 1일 때에 대한 처리를 한 거라 그 부분을 손봐야 한다. 

 

def isprime(a):
    sqrt = int(a ** 0.5)
    if a <= 1: 
        return False
    for i in range(2,sqrt+1):
        if a % i == 0:
            return False
    else: 
        return True
# a == 1을 a <= 1로 바꿨다. 
a = [i for i in range(100) if isprime(i)]
print(a)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

함수의 세번째 줄에 있는 ==를 <=로 바꾸면 2부터 나오는 것을 볼 수 있다. 

 

b = list(i for i in range(100) if i % 3 == 0)
print(b)
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99]

물론 이런 것도 된다. 

 

한번에 여러 개 쓰기

a = [i * j for i in range(1,11) for j in range(1,5,2)]
print(a)
[1, 3, 2, 6, 3, 9, 4, 12, 5, 15, 6, 18, 7, 21, 8, 24, 9, 27, 10, 30]

반복문이 여러개 있을 때 처리는 뒤에놈부터다. 즉, 이 코드는 뒤에 있는 j(1,3)를 앞에 있는 i에 순차적으로 곱한 결과. 

 

a = [i for i in range(1,101) if i % 2 == 0 and i % 4 == 2]
print(a)
[2, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 66, 70, 74, 78, 82, 86, 90, 94, 98]

조건문도 여러 개 넣을 수 있다. 위 코드는 2의 배수이면서 4의 배수가 아닌 수를 찾는 코드. 

 

a = [i for i in range(1,101) if i % 2 == 0 if i % 3 == 0]
print(a)
[6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96]

2와 3의 공배수, 즉 6의 배수를 찾는 코드. ...근데 이게 이렇게 된다고? 저거 실화냐 


번외편-어? 이게 된다고? 

a = ['{},{}'.format(i,j) for i in range(1,10) for j in range(1,10,2)]
print(a)
['1,1', '1,3', '1,5', '1,7', '1,9', '2,1', '2,3', '2,5', '2,7', '2,9', '3,1', '3,3', '3,5', '3,7', '3,9', '4,1', '4,3', '4,5', '4,7', '4,9', '5,1', '5,3', '5,5', '5,7', '5,9', '6,1', '6,3', '6,5', '6,7', '6,9', '7,1', '7,3', '7,5', '7,7', '7,9', '8,1', '8,3', '8,5', '8,7', '8,9', '9,1', '9,3', '9,5', '9,7', '9,9']

포맷 줘서 문자열을 리스트에 넣는 것도 된다. 

 

a = ['{},{}'.format(i,j) for i in range(1,10) for j in 'pikachu']
print(a)
['1,p', '1,i', '1,k', '1,a', '1,c', '1,h', '1,u', '2,p', '2,i', '2,k', '2,a', '2,c', '2,h', '2,u', '3,p', '3,i', '3,k', '3,a', '3,c', '3,h', '3,u', '4,p', '4,i', '4,k', '4,a', '4,c', '4,h', '4,u', '5,p', '5,i', '5,k', '5,a', '5,c', '5,h', '5,u', '6,p', '6,i', '6,k', '6,a', '6,c', '6,h', '6,u', '7,p', '7,i', '7,k', '7,a', '7,c', '7,h', '7,u', '8,p', '8,i', '8,k', '8,a', '8,c', '8,h', '8,u', '9,p', '9,i', '9,k', '9,a', '9,c', '9,h', '9,u']

파이썬은 문자열도 시퀀스 데이터라 for문을 돌릴 수 있어서 저게 된다. 

 

a = [ord(i) for i in 'ABCDEFG']
print(a)
a = [hex(ord(i)) for i in 'ABCDEFG']
print(a)

알파벳의 ASCII 코드 번호를 뽑거나 그 코드 진수 바꾸는 것도 된다. 

 

번외편 2-튜플도 되나요? 

a = (i for i in 'pikachu')
print(type(a))
<class 'generator'>

아뇨 안되는데요. 저거 뽑을 수는 있는데 

a = (i for i in range(1,10))
for i in a:
    print(i)

for문 줘야 한다. (예전에 Biopython할 때 저런거 많이 봤는데 죄다 for문으로 뽑더라...)

 

a = 'Eternatus'
b = tuple(ord(i) for i in a)
print(b)

참고로 얘는 된다. 소괄호 말고 쟤. 

 

번외편 3-세트와 딕셔너리에도 해봤습니다

a = {i for i in range(10)}
print(a)
a = set(i for i in 'apple')
print(a)

세트의 경우 둘 다 생성하는 방식이다. 아무튼... 

 

a = {i:j for i in range(9) for j in range(9) if i % 2 == 0)
print(a)

딕셔너리는 되긴 되는데 키값이 중복되면 앞에걸 버리는 특성상 리스트나 튜플보다는 길이가 짧다. 

'Coding > Python' 카테고리의 다른 글

순열조합  (0) 2022.08.22
워드클라우드 코드에 기능 추가  (0) 2022.08.22
완전수 찾는 코드  (0) 2022.08.22
Project restriction enzyme: 패치노트  (0) 2022.08.22
Cutter, Finder 공통 패치: FASTA 파일 불러오는 기능  (0) 2022.08.22
Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

완전수 찾는 코드

Coding/Python 2022. 8. 22. 00:36

이거 근데 우분투 놋북이 뭐가 불만인지 키보드가 안먹히데... 
커널 올려줘도 난리여... 

안그래도 오늘 진상 만나서 힘들었는데 너까지 왜그러냐... 


import sys
a = int(sys.stdin.readline())
yaksu = []
for i in range(1,a+1):
    if a % i == 0:
        yaksu.append(i)
yaksu_text = ''.join(str(yaksu))
print('{}의 약수는 {}입니다. '.format(a,yaksu_text))
if sum(yaksu) == 2 * a:
    print('{}는 자기 자신을 제외한 약수들의 합이 {}와 동일하므로 완전수입니다. '.format(a,a))

전체 코드는 뜯어보고 자시고 할 것도 없음. 완전수는 자기 자신을 제외한 모든 약수들을 더했을 때 자기 자신이 나와야 완전수이고 6과 28이 대표적인 완전수임. (1+2+3=6, 1+2+4+7+14=28) 여기까지만 봤을 때 그래서 곱하기 2를 넣은건가? 하고 감이 오시는 분도 계시겠지만 자기 자신을 제외하고 자기 자신과 합이 같다=모든 약수를 더했을 때 합이 자기 자신의 두 배라는 얘기임. 즉 6은 1+2+3+6=12(6+6=12), 28은 1+2+4+7+14+28=56(1+2+4+7+14=28)이라는 얘기. 참 쉽죠?

로직 자체는 쉬워요 갑자기 키보드가 안먹어서 글치...

 

진지하게 다음달에 월급타면 놋북 알아봐야 하나 고민했음... 이거 셋업도 귀찮은데.

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

Project restriction enzyme: 패치노트

Coding/Python 2022. 8. 22. 00:35

NEB Filter 추가

이제 NEB에서 파는 제한효소들만 볼 수 있습니다. (NEB: 뉴 잉글랜드 바이오랩스. NEB cutter 만든 거기 맞음)

 

Cutter/Finder의 저장 형식 변경

일부 저장 형식이 변경되었습니다. 

Cutter
Finder
Searcher(하는김에 수정)

 

저장 디렉토리 출력

저장 시 현재 디렉토리를 출력해줍니다. 

 

FASTA파일 관련 문제 수정

1. FASTA 파일에 시퀀스가 소문자로 기록되어 있을 경우 제대로 못 찾던 문제를 수정했습니다. 
2. FASTA 파일에 >가 여러개 일 경우 에러가 뜨는 대신 맨 위에 있는 >로 진행합니다. 

참고로 왜 NEB냐면 거기껄 제일 많이 썼음. 

 

Genbank 파일 지원

문제가 하나 있는데 리드랑 파스랑 뭔 차인지 모르겠음. FASTA는 지에딧으로 열리는거라 보기라도 했지... Genbank는 gb파일이라 우분투에서 못열어요... 게임보이 어드밴스 파일이래... 

혹시 차이 아시는 분 제보 바랍니다. 일단 Read Parse는 FASTA랑 비슷하게 돌아감. 

 

기타 수정사항

1. 커터 파인더 공통으로 FASTA, Genbank를 불러올 경우 description영역에 있는 부분도 가져와서 기록합니다. 수동 입력의 경우 수동입력으로 따로 저장됩니다. 
2. 커터의 경우 효소 하나당 최소 두 줄 차지합니다. (이름/시퀀스/컷수 + 어디)

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

Cutter, Finder 공통 패치: FASTA 파일 불러오는 기능

Coding/Python 2022. 8. 22. 00:31

패치노트

1. 꺾쇠(>)가 하나인 FASTA 파일 한정으로 읽어올 수 있습니다. (Biopython이 꺾쇠 개수에 따라 불러오는 방식이 다름)

2. FASTA 파일을 불러올 경우, 시퀀스 이름란에 FASTA file의 ID영역이 들어갑니다. (사실 description 넣으려다가 너무 길어서...)

3. FASTA 파일을 불러오는 데 성공할 경우에도 멘트가 출력됩니다. (실패할때는 당연히 출력됨)


개고생의 흔적

from argparse import FileType
import tkinter
from tkinter import filedialog
from Bio import SeqIO
# 정신사나워서 불러오는거랑 표 분리했습니다...OTL

이쪽이 모듈이다. (뭐가 많음)

 

FASTA_open = input('FASTA 파일을 불러오시겠습니까? 불러오실거면 FASTA 혹은 fasta를 임력해주세요. ').upper()
if FASTA_open == 'FASTA':
    root = tkinter.Tk()
    root.withdraw()
    dir_path = filedialog.askopenfilename(parent=root,initialdir="/home/koreanraichu",title='Please select a directory',filetypes = (("*.fasta","*fasta"),("*.faa","*faa")))
    try: 
        fasta_read = SeqIO.read(dir_path,'fasta')
        sequence_name = fasta_read.id
        sequence = str(fasta_read.seq)
        # 단식으로만 가져오게 함. 
        print(dir_path,'FASTA 파일을 가져왔습니다! ')
    except: 
        print('이 FASTA파일은 한 파일에 여러 개가 기록되어 있어서 가져올 수 없습니다! ')
        # 그래서 parse로 가져와야 하는 파일이면 에러떠여 
else: 
    sequence_name = input("검색할 시퀀스의 이름을 입력해주세요: ")
    sequence = input("검색할 시퀀스를 입력해주세요: ")
    # 시퀀스 입력하는 란

Finder의 경우 효소 변수도 저 위로 빼버렸다. 

 

Cutter(with FASTA)
Finder(with FASTA)

이거 사용자가 FASTA 입력한건지 직접 입력한건지도 써 주면 좋을 듯 하다. 그거랑 별개로 Cutter에 NEB에서 파는효소 or 전체 효소로 필터 주는 것도 재밌을듯. NEB 의문의 홍보행 

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

Finder 기능추가: 정규식 도입

Coding/Python 2022. 8. 22. 00:29

정말! 개 노가다끝에... 드디어 해냈음... 


AccI, 정규식 필요
EcoRI, 정규식 불필요


일단 도입하는 것 자체는 커터에서 했기때문에 크게 어려운 부분은 없었고, 문제가 좀 있었다. 

1. 함수 정의하고 뺑뺑이를 돌렸는데 알파벳이 자꾸 하나만 바뀌는 문제(수정함) 
2. 정규식은 찾아바꾸기가 안된다. (sub()은 토씨 하나 안 틀리고 바꿔주는거라 G..T로 찾고 G..T/로 바꾸면 모든 시퀀스가 죄다 G..T/로 바뀐다)

첫 번째 문제는 해결했고 두번째 문제의 경우 찾아바꾸기가 안돼서 정규식이 필요한 효소들은 어떻게 자르는지가 위에만 표시되어 있다. 살려줘요. 

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

방명록