(198)

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

재귀함수는 정의할 때 자기자신을 재참조한다고 했는데, 정의하는데 자기자신이 들어가면 대체 어떻게 돌아가는지 알아보자. 라이츄가 라이츄를 꺼내고 그 라이츄가 라이츄를 꺼내고 팩토리얼 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/로 바뀐다) 첫 번째 문제는 해결했고 두번째 문제의 경우 찾아바꾸기가 안돼서 정규식이 필요한 효소들은 어떻게 자르는지가 위에만 표시되어 있다. 살려줘요.

정규식(Regular Expression)-re모듈 사용법

분량+저녁크리로 인해 2부작으로 나눠버림... 이 글의 re모듈은 파이썬에서 사용하는거지만, 앞 글에 있는 기호와 메타문자는 언어를 불문하고 정규 표현식에서 다 쓰인다. https://koreanraichu.tistory.com/118 정규식(Regular Expression)-기호와 메타문자 문자 찾는 것 자체는 find()도 해주는데, 얘는 딱 정확하게 일치하는 문자열만 찾아준다. 그럼 정규식은? 그건 대충 와일드카드같은 거다. 그러니까 find()는 소라빵 찐빵 팥빵 붕 koreanraichu.tistory.com 다른 언어를 사용한다고 해도 앞 글은 한번정도는 읽어보자. re.search() 자... 전에도 서술했지만, find()는 정규식을 주면 그 정규식이랑 일치하는 걸 찾지 정규식으로 검색하..

정규식(Regular Expression)-기호와 메타문자

문자 찾는 것 자체는 find()도 해주는데, 얘는 딱 정확하게 일치하는 문자열만 찾아준다. 그럼 정규식은? 그건 대충 와일드카드같은 거다. 그러니까 find()는 소라빵 찐빵 팥빵 붕어빵 이런 식으로 딱딱 키워드를 찾는거고 정규식은 *빵으로 소라빵 찐빵 붕어빵 팥빵 다 찾는 거지. 참고로 정규식을 쓰려면 re를 불러야 한다. import re ㄱㄱ 정규식 문자 정규식에서 쓰는 문자들과 이게 뭐 하는건지를 간단히 알아보자. . Wildcard(구글 검색에서 *) for i in range(len(pokemon)): if re.search('김.',pokemon[i]): print(pokemon[i]) 김부추 김후추 김양상추 박알타리김치 고등어김치찜 김배추 참고로 전부 본인 포켓몬 이름임. 왜요 ^ ~로 ..

Cutter 기능 추가: 정규식 도입

Finder는 도입하려면 좀 걸립니다... 얘는 아예 정규식+찾아바꾸기가 필요한거라...... 정규식 도입 import pandas as pd import re from datetime import datetime enzyme_table = pd.read_csv('/home/koreanraichu/restriction.csv') enzyme_table2 = pd.read_csv('/home/koreanraichu/restriction_RE.csv') # 정규식 도입을 위해... 어쩔 수 없이 합쳤음... enzyme_table = pd.concat([enzyme_table,enzyme_table2]) enzyme_table = enzyme_table.sort_values('Enzyme') enzyme_t..

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

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 라이츄

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

정규식(Regular Expression)-re모듈 사용법

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

분량+저녁크리로 인해 2부작으로 나눠버림... 

 

이 글의 re모듈은 파이썬에서 사용하는거지만, 앞 글에 있는 기호와 메타문자는 언어를 불문하고 정규 표현식에서 다 쓰인다. 

https://koreanraichu.tistory.com/118

 

정규식(Regular Expression)-기호와 메타문자

문자 찾는 것 자체는 find()도 해주는데, 얘는 딱 정확하게 일치하는 문자열만 찾아준다. 그럼 정규식은? 그건 대충 와일드카드같은 거다. 그러니까 find()는 소라빵 찐빵 팥빵 붕

koreanraichu.tistory.com

다른 언어를 사용한다고 해도 앞 글은 한번정도는 읽어보자. 


re.search()

자... 전에도 서술했지만, find()는 정규식을 주면 그 정규식이랑 일치하는 걸 찾지 정규식으로 검색하질 않아요... 

 

print(re.search('G...',DNA))
<re.Match object; span=(1, 5), match='GAGG'>

단식

 

for i in range(len(df)):
    enzyme = df['Enzyme'][i]
    if re.search('A.....',enzyme):
        print(enzyme)
Acc36I
AccB1I
AccB2I
AccB7I
AceIII
AflIII
Alw21I
Alw26I
Ama87I
AmaCSI
ApaORI
AquIII
Asp10HII
Asp26HI
Asp27HI
Asp35HI
Asp36HI
Asp40HI
Asp50HI
Asp700I
Asp745I
Asp59I
AsuIII
AsuC2I
AsuHPI

복식

일단 자세한건 re.match()에서 서술하겠지만, 일단 re.search()가 정규식 검색할 때 쓰는 게 맞다. 

 

re.match()

print(re.match('G...',DNA))
None

re.search()와 달리 re.match()는 처음부터 정규식 형식이랑 일치하는 걸 찾아준다. 쟤가 그래서 왜 None이냐... 

DNA="AGAGGTTAAAGAACAAAGGCTTACTGTGCGCAGAGGAACGCCCATTTAGCGGCTGGCGTTTTGAATCCTCGGTCCCCCTTGTCTATCCAGATTAATCCAATTCCCTCATTTAGGACCCTACCAAGTCAACATTGGTATATGAATGCGACCTCGAAGAGGCCGCCTAAAAATGACAGTGGTTGGTGCTCTAAACTTCATTTGGTTAACTCGTGTATCAGCGCGATAGGCTGTTAGAGGTTTAATATTGTATGGCAAGGTACTTCCGGTCTTAATGAATGGCCGGGAAAGGTACGCACGCGGTATGGGGGGGTGAAGGGGCGAATAGACAGGCTCCCCTCTCACTCGCTAGGAGGCAATTGTATAAGAATGCATACTGCATCGATACATAAAACGTCTCCATCGCTTGCCCAAGTTGTGAAGTGTCTATCACCCCTAGGCCCGTTTCCCGCATATTAACGCCTGATTGTATCCGCATTTGATGCTACCGTGGTTGAGTCAGCGTCGAGCACGCGGCACTTATTGCATGAGTAGAGTTGACTAAGAGCCGTTAGATGCCTCGCTGTACTAATAGTTGTCGACAGATCGTCAAGATTAGAAAACGGTAGCAGCATTATCGGAGGTTCTCTAACTAGTATGGATAGCCGTGTCTTCACTGTGCTGCGGCTACCCATCGCCTGAAAACCAGTTGGTGTTAAGCGATCCCCTGTCCAGGACGCCACACGTAGTGAAACATACACGTTCGTCGGGTTCACCCGGGTCGGATCTGAGTCGACCAAGGACACACTCGAGCTCCGATCCCTACTGTCGAGAAATTTGTATCCCGCCCCCGCAGCTTGCCAGCTCTTTGAGTATCATGGAGCCCATGGTTGAATGAGTCCAATAACGAACTTCGACATGATAAAGTCCCCCCCTCGCGACTTCCAGAGAAGAAGACTACTGAGTTGAGCGTTCCCAGCACTTCAGCCAAGGAAGTTACCAATTTTTAGTTTCCGAGTGACAC"

원본 시퀀스가 이거였음. G로 시작하는 게 첫 번째 글자가 아니라 두 번째 글자기때문에 첫 빠따부터 에이 뭐야 없어가 되버린다. 

 

print(re.match('.G...',DNA))
print(re.search('.G...',DNA))
<re.Match object; span=(0, 5), match='AGAGG'>
<re.Match object; span=(0, 5), match='AGAGG'>

이거는 둘 다 똑같은 결과가 나온다. (정규식 형식은 어쨌든 일치하므로)

 

re,match()의 메소드들

이거 참고로 단독소환 쌉가능. 

 

records = re.finditer('A.{4}C',DNA)
for r in records:
    print(r.group(),r.start(),r.end(),r.span())

finditer에 대해서는 밑에서 또 설명할 예정이니까 이것부터 보고 갑시다. 저기 r.뭐시기 된 저거요. 저게 re.match의 메소드인데 순서대로 

1) 그룹(문자열)
2) 시작
3) 끝
4) span

이렇게 된다. 출력은 

AAGAAC 8 14 (8, 14)

이렇게 된다. 

 

re.findall()

이름을 보면 아시겠지만 그냥 다 찾아주는 애다. 반복문 데려 올 필요도 없다. 

 

print(re.findall('G...',DNA))
['GAGG', 'GAAC', 'GGCT', 'GTGC', 'GCAG', 'GGAA', 'GCCC', 'GCGG', 'GGCG', 'GAAT', 'GGTC', 'GTCT', 'GATT', 'GGAC', 'GTCA', 'GGTA', 'GAAT', 'GCGA', 'GAAG', 'GGCC', 'GCCT', 'GACA', 'GTGG', 'GGTG', 'GGTT', 'GTGT', 'GCGC', 'GATA', 'GGCT', 'GTTA', 'GAGG', 'GTAT', 'GGCA', 'GGTA', 'GGTC', 'GAAT', 'GGCC', 'GGGA', 'GGTA', 'GCAC', 'GCGG', 'GGGG', 'GGGT', 'GAAG', 'GGGC', 'GAAT', 'GACA', 'GGCT', 'GCTA', 'GGAG', 'GCAA', 'GTAT', 'GAAT', 'GCAT', 'GCAT', 'GATA', 'GTCT', 'GCTT', 'GCCC', 'GTTG', 'GAAG', 'GTCT', 'GGCC', 'GTTT', 'GCAT', 'GCCT', 'GATT', 'GTAT', 'GCAT', 'GATG', 'GTGG', 'GAGT', 'GCGT', 'GAGC', 'GCGG', 'GCAT', 'GAGT', 'GAGT', 'GACT', 'GAGC', 'GTTA', 'GATG', 'GCTG', 'GTTG', 'GACA', 'GATC', 'GTCA', 'GATT', 'GAAA', 'GGTA', 'GCAG', 'GGAG', 'GTTC', 'GTAT', 'GGAT', 'GCCG', 'GTCT', 'GTGC', 'GCGG', 'GCCT', 'GAAA', 'GTTG', 'GTGT', 'GCGA', 'GTCC', 'GGAC', 'GCCA', 'GTAG', 'GAAA', 'GTTC', 'GTCG', 'GGTT', 'GGGT', 'GGAT', 'GAGT', 'GACC', 'GGAC', 'GAGC', 'GATC', 'GTCG', 'GAAA', 'GTAT', 'GCCC', 'GCAG', 'GCCA', 'GCTC', 'GAGT', 'GGAG', 'GGTT', 'GAAT', 'GAGT', 'GAAC', 'GACA', 'GATA', 'GTCC', 'GCGA', 'GAGA', 'GAAG', 'GAGT', 'GAGC', 'GTTC', 'GCAC', 'GCCA', 'GGAA', 'GTTA', 'GTTT', 'GAGT', 'GACA']

근데 위치까지 준다고는 안 했다. 

 

re.finditer()

print(re.finditer('A..C',DNA))
<callable_iterator object at 0x7f009c5f8100>

얘는 다른 메소드들처럼 걍 쌩으로 print문에 넣으면 안된다. 저렇게 뜬다. 

 

records = re.finditer('A..C',DNA)
for r in records:
    print(r)
<re.Match object; span=(16, 20), match='AGGC'>
<re.Match object; span=(37, 41), match='ACGC'>
<re.Match object; span=(63, 67), match='AATC'>
<re.Match object; span=(84, 88), match='ATCC'>
<re.Match object; span=(93, 97), match='AATC'>
<re.Match object; span=(99, 103), match='ATTC'>
<re.Match object; span=(114, 118), match='ACCC'>
<re.Match object; span=(123, 127), match='AGTC'>
<re.Match object; span=(142, 146), match='ATGC'>
<re.Match object; span=(156, 160), match='AGGC'>
<re.Match object; span=(189, 193), match='AAAC'>
<re.Match object; span=(205, 209), match='ACTC'>
<re.Match object; span=(224, 228), match='AGGC'>
<re.Match object; span=(290, 294), match='ACGC'>
<re.Match object; span=(294, 298), match='ACGC'>
<re.Match object; span=(323, 327), match='AGAC'>
<re.Match object; span=(327, 331), match='AGGC'>
<re.Match object; span=(340, 344), match='ACTC'>
<re.Match object; span=(350, 354), match='AGGC'>
<re.Match object; span=(366, 370), match='ATGC'>
<re.Match object; span=(370, 374), match='ATAC'>
<re.Match object; span=(381, 385), match='ATAC'>
<re.Match object; span=(388, 392), match='AAAC'>
<re.Match object; span=(428, 432), match='ACCC'>
<re.Match object; span=(434, 438), match='AGGC'>
<re.Match object; span=(455, 459), match='ACGC'>
<re.Match object; span=(467, 471), match='ATCC'>
<re.Match object; span=(478, 482), match='ATGC'>
<re.Match object; span=(493, 497), match='AGTC'>
<re.Match object; span=(507, 511), match='ACGC'>
<re.Match object; span=(542, 546), match='AGCC'>
<re.Match object; span=(551, 555), match='ATGC'>
<re.Match object; span=(596, 600), match='AAAC'>
<re.Match object; span=(639, 643), match='AGCC'>
<re.Match object; span=(665, 669), match='ACCC'>
<re.Match object; span=(678, 682), match='AAAC'>
<re.Match object; span=(693, 697), match='AAGC'>
<re.Match object; span=(698, 702), match='ATCC'>
<re.Match object; span=(712, 716), match='ACGC'>
<re.Match object; span=(717, 721), match='ACAC'>
<re.Match object; span=(727, 731), match='AAAC'>
<re.Match object; span=(731, 735), match='ATAC'>
<re.Match object; span=(750, 754), match='ACCC'>
<re.Match object; span=(766, 770), match='AGTC'>
<re.Match object; span=(778, 782), match='ACAC'>
<re.Match object; span=(782, 786), match='ACTC'>
<re.Match object; span=(794, 798), match='ATCC'>
<re.Match object; span=(817, 821), match='ATCC'>
<re.Match object; span=(857, 861), match='AGCC'>
<re.Match object; span=(873, 877), match='AGTC'>
<re.Match object; span=(901, 905), match='AGTC'>
<re.Match object; span=(930, 934), match='AGAC'>
<re.Match object; span=(961, 965), match='AGCC'>
<re.Match object; span=(996, 1000), match='ACAC'>

Biopython에서 parse로 불러오는것마냥 for문이 필요하다. 

 

전방탐색

text='http://localhost:8888/notebooks/re.search.ipynb'

이런 텍스트가 있을 때 

p = re.compile(".+:")
print(p.search(text))

보통은 이렇게 찾는다. 근데 이 방식에는 문제가 있어요... 정규식이 복잡해지면 정규식 짜다가 

이러고 밥상 엎는다. 

 

긍정형 전방 탐색

p = re.compile(".+(?=:)")
print(p.search(text))
<re.Match object; span=(0, 16), match='http://localhost'>

?=가 들어가는 것. 저 식의 경우 :가 있으면 응 있네 여이따 하고 찾아는 주지만 출력을 안 한다. (저거는 Jupyter URL로 해서 그렇다)

 

부정형 전방 탐색

여러분들은 불신의 아이콘에 대해 아시는가? 

얘 맞다. 

그러니까 이런 거. 

 

블로그에서 뭔가를 검색했는 데 저게 보이면 일단 거르고 보잖음. 근데 쟤랑 그거랑 뭔 상관이냐고? 자, 생각해봅시다... 일반적으로 맛집을 찾을 때 저런 바이럴들이 많이 나오니까 우리는 저것들을 피하기 위한 키워드를 정해서 맛집을 찾잖음? (오빠랑 맛집 뭐 이런걸로다가) 부정형 전방 탐색은 맛집 검색을 하면서 아예 저 불신의 아이콘을 빼버리고 찾는 거라고 보면 됨. 

 

file_list=['buchu.jpg','moon.jpg','text.txt','py.py','BOJ.ipynb','jemok.png','pyo.csv']

그러니까 이런 파일들이 있을 때 jpg파일을 빼려면 txt, py, ipynb, png, csv파일을 묶어야 하는데 정규식에 어느 세월에 저걸 다 쓰고 앉았음? 

for i in file_list:
    if re.match('.*[.](?!jpg$).*$',i):
        print(i)
text.txt
py.py
BOJ.ipynb
jemok.png
pyo.csv

이럴 때 부정형 전방탐색으로 jpg를 빼버리면 된다. 정확히는 jpg가 포함되지 않은 것만 보여준다. 

 

sub(), subn()

p=re.compile('W')
p.sub('[A|T]','CCWGG')

이런 식으로 쓰면 W가 A or T로 바뀌어서 나온다. 

 

p=re.compile('N')
p.sub('.','GATNNNATCNNNNNNNN',count=3)

이런 식으로 바꿀 횟수를 지정하는 것도 가능하다. (count=n)

 

('GAT...ATC........', 11)

subn()도 쓰는 방법은 비슷한데, 얘는 반환 형태가 튜플이고 몇 글자 바꿨는지가 나온다. 

 

re.compile()

정규식 일일이 쓰기 귀찮을 때 쓰면 좋다. 

 

p = re.compile('G....C')
print(p.search(DNA))

compile에 옵션을 지정하고, 그 다음 match나 search, 파인드올 돌리면 된다. 

p = re.compile('t.....t',re.I)
print(p.findall(DNA))

옵션은 이런 식으로 붙고, 총 네 개가 있다. 

 

re.compile()의 옵션

1)Dotall(S):와일드카드를 ㄹㅇ 와일드카드로 쓸 수 있다. 저 옵션이 없으면 개행문자는 와일드카드로 대체가 안되는데, 저 옵션을 붙여벼리면 아 그런건 모르겠고 와일드카드! 가 된다. 

2) Ignorecase(I): 대소문자를 무시하고 그냥 일치하는 문자열을 찾아준다. 그러니까 저 옵션을 주면 A랑 a랑 같아진다. (원래 파이썬은 대소문자 칼같이 구별한다) 

3) Multiline(M): 여러 줄로 된 문자열을 줄단위로 인식한다. 그러니까 이게 무슨 말이냐... 

나 보기가 역겨워
가실 때에는
말없이 고이 보내 드리오리다
 
영변에 약산
진달래꽃
아름 따다 가실 길에 뿌리오리다
  
가시는 걸음걸음
놓인 그 꽃을
사뿐히 즈려밟고 가시옵소서
 
나 보기가 역겨워
가실 때에는
죽어도 아니 눈물 흘리오리다

이 시는 김소월의 진달래꽃이다. 마야 아니다 우리가 볼 때는 4연이고 각 연마다 3행인데, Multiline이 없는 정규식 처리에서는 저걸 그냥 한 줄로 본다. 행이고 연이고 그런건 모르겠고 걍 한줄이여! 이렇게 되버리는데 Multiline 옵션이 들어가면 12줄짜리 텍스트(연과 연 사이 개행문자 포함 15줄)로 본다. 

 

4) Verbose(X): 정규식에 주석을 넣을 수 있다. 코드와 마찬가지로 정규식도 복잡해지면 

이렇게 된다. (아니면 머리에 블루스크린이 뜨거나) Verbose 옵션을 주면 그걸 방지하고자 주서을 넣을 수 있게 된다. 

Lv. 35 라이츄

Lv. 35 라이츄

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

정규식(Regular Expression)-기호와 메타문자

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

문자 찾는 것 자체는 find()도 해주는데, 얘는 딱 정확하게 일치하는 문자열만 찾아준다. 그럼 정규식은? 그건 대충 와일드카드같은 거다. 그러니까 find()는 소라빵 찐빵 팥빵 붕어빵 이런 식으로 딱딱 키워드를 찾는거고 정규식은 *빵으로 소라빵 찐빵 붕어빵 팥빵 다 찾는 거지. 

참고로 정규식을 쓰려면 re를 불러야 한다. 

import re

ㄱㄱ


정규식 문자

정규식에서 쓰는 문자들과 이게 뭐 하는건지를 간단히 알아보자. 

 

.

Wildcard(구글 검색에서 *)

 

for i in range(len(pokemon)):
    if re.search('김.',pokemon[i]):
        print(pokemon[i])
김부추
김후추
김양상추
박알타리김치
고등어김치찜
김배추

참고로 전부 본인 포켓몬 이름임. 왜요 

 

^

~로 시작하는 단어

 

for i in range(len(pokemon)):
    if re.search('^김',pokemon[i]):
        print(pokemon[i])
김부추
김후추
김양상추
김배추

꺾쇠가 들어가면 ~로 시작하는 단어를 찾아달라는 얘기. 꺾쇠를 단어 앞에 쓴다. 

 

$

for i in range(len(pokemon)):
    if re.search('!$',pokemon[i]):
        print(pokemon[i])
앗!잘못던짐!
고객님!

~로 끝나는 단어를 찾아달라는 얘기. 달러를 뒤에 쓴다. 이거 ^랑 헷갈리면 안된다. 

 

|

for i in range(len(df)):
    enzyme = df['Enzyme'][i]
    sequence = df['sequence'][i]
    if re.search('W|S',sequence):
        print(enzyme,sequence)

OR. 햄버거|피자는 햄버거 or 피자라는 얘기. 참고로 대문자 I나 소문자 L이 아니고 쉬프트+백슬래시(\)이다. 

 

[ ]

for i in range(len(df)):
    enzyme = df['Enzyme'][i]
    sequence = df['sequence'][i]
    if re.search('[NSW]',sequence):
        print(enzyme,sequence)

일단 하는 역할 자체는 OR이랑 비슷하다. 대괄호 안에 있는것들 중 하나를 포함하고 있는 것. Cutter에 있는 제한효소 인식 시퀀스도 전부 대괄호로 치환한 것. 

 

[^]

for i in range(len(df)):
    enzyme = df['Enzyme'][i]
    sequence = df['sequence'][i]
    if re.search('^Ba[^c]',enzyme):
        print(enzyme,sequence)
BaeI ACNNNNGTAYC
Bal228I GGNCC
BamNII GGWCC
BanI GGYRCC
BanII GRGCYC
BasI CCANNNNNTGG
BavAII GGNCC
BavBII GGNCC

쓰는 법은 일반적인 ^ 쓰는것처럼 앞에 붙이면 된다. 단, 대괄호 안에 있는 꺾쇠는 [] 안에 있는것들 중 쟤는 빼라는 얘기. 

 

[-]

어디부터 어디까지라고 지정하는 것.

[a-z] : 영어 문자의 모든 범위를 지정한다.
[가-힣] : 한글 문자의 모든 범위를 지정한다.
[0-9] : 숫자의 모든 범위를 지정한다.

 

( )

for i in range(len(df)):
    enzyme = df['Enzyme'][i]
    sequence = df['sequence'][i]
    if re.search('(Eco)',enzyme):
        print(enzyme,sequence)
Eco24I GRGCYC
Eco31I GGTCTC
Eco47I GGWCC
Eco57I CTGAAG
Eco64I GGYRCC
Eco81I CCTNAGG
Eco88I CYCGRG
Eco91I GGTNACC
Eco130I CCWWGG
Eco1831I CCSGG
EcoA4I GGTCTC
EcoHI CCSGG
EcoHK31I YGGCCR
Eco75KI GRGCYC
Eco57MI CTCRAG
EcoNI CCTNNNNNAGG
EcoO44I GGTCTC
EcoO65I GGTNACC
EcoO109I RGGNCCY
EcoO128I GGTNACC
EcoP15I CACGAG
EcoR124II GAANNNNNNNRTCG
EcoRII CCWGG
EcoT14I CCWWGG
EcoT38I GRGCYC
Eco13kI CCNGG
Eco21kI CCNGG
Eco27kI CYCGRG
Eco137kI CCNGG

괄호 안에 있는 걸 그룹으로 묶어서 찾는다. [붕어빵]은 붕 아님 어 아님 빵 들어간건 다 찾아주는데 (붕어빵)은 붕어빵만 찾는다. 

 

메타 문자

백슬래시 뒤에 뭔가 오는 것. 

 

\d, \D

숫자 포함, 숫자 제외

 

for i in range(len(pokemon)):
    if re.search('\d',pokemon[i]):
        print(pokemon[i])
대포동1호
김2번척추씨

대포동1호 뭐예요 제 파이어로요

 

for i in range(len(df)):
    enzyme = df['Enzyme'][i]
    sequence = df['sequence'][i]
    if re.search('^A..\D',enzyme):
        print(enzyme,sequence)
AarI CACCTGC
AccI GTMKAC
AccB1I GGYRCC
AccB2I RGCGCY
AccB7I CCANNNNNTGG
AceI GCWGC
AceIII CAGCTC
AclWI GGATC
AcoI YGGCCR
AcpII CCANNNNNTGG
AcrII GGTNACC
AcsI RAATTY
AcuI CTGAAG
AcyI GRCGYC
AdeI CACNNNGTG
AeuI CCWGG
AfiI CCNNNNNNNGG
AflI GGWCC
AflIII ACRYGT
AglI CCWGG
AgsI TTSAA
AhaI CCSGG
AhaII GRCGYC
AhdI GACNNNNNGTC
AjnI CCWGG
AjuI GAANNNNNNNTTGG
AlfI GCANNNNNNTGC
AloI GAACNNNNNNTCC
AlwI GGATC
AlwNI CAGNNNCTG
AlwXI GCAGC
AmaCSI GCTCCA
AocI CCTNAGG
AocII GDGCHC
AorI CCWGG
AosII GRCGYC
ApaBI GCANNNNNTGC
ApaORI CCWGG
ApeKI GCWGC
ApoI RAATTY
ApyI CCWGG
ApyPI ATCGAC
AquI CTCGRG
AquII GCCGNAC
AquIII GAGGAG
AquIV GRGGAAG
ArsI GACNNNNNNTTYG
AseII CCSGG
AspI GACNNNGTC
AspAI GGTNACC
AspEI GACNNNNNGTC
AspHI GWGCWC
AspNI GGNNCC
AstWI GRCGYC
AsuI GGNCC
AsuIII GRCGYC
AsuC2I CCSGG
AsuHPI GGTGA
AtsI GACNNNGTC
AvaI CYCGRG
AvaII GGWCC
AvcI GGNCC

소문자 d는 숫자 포함이고 대문자 D는 제외이다. 근데 이 케이스의 경우 ^A..\D보다는 .에 반복 주고 \D로 쓰는 쪽이 더 나을듯... 알파벳 두 글자 이후로 숫자가 오는 제한효소는 리스트업이 안됐는데, AsuC2I처럼 알파벳 세글자 다음에 숫자가 있는 제한효소는 나왔다. 

 

\s, \S

for i in range(len(list_n)):
    if re.search('a\s',list_n[i]):
        print(list_n[i])
a bc
a b c

이게 \s(공백 포함)

 

for i in range(len(list_n)):
    if re.search('a\S',list_n[i]):
        print(list_n[i])
abc
ab c
abab

얘는 \S(공백 제외)이다. 

 

\b, \B

이건 설명하기가 좀 애매한디... 

 

text='he said checkmate for my class mate, before she move her knight.'

이 구문이 있을 때 

 

p = re.compile(r'\bmate')
p.search(text)

이걸 치면 class mate의 mate가 나온다. 

p = re.compile(r'\Bmate')
p.search(text)

이렇게 주면 checkmate의 mate가 나온다. 얘는 단어와 단어 사이의 공백을 따지기 때문. 

 

\w, \W

각각 숫자와 알파벳, 숫자와 알파벳 제외. 

 

for i in range(len(df)):
    enzyme = df['Enzyme'][i]
    sequence = df['sequence'][i]
    if re.search('^X..\w',enzyme):
        print(enzyme,sequence)
XagI CCTNNNNNAGG
XapI RAATTY
XceI RCATGY
XcmI CCANNNNNNNNNTGG
XhoII RGATCY
XmiI GTMKAC
XmnI GAANNNNTTC

이게 \w고 

 

for i in range(len(df)):
    enzyme = df['Enzyme'][i]
    sequence = df['sequence'][i]
    if re.search('^X..\W',enzyme):
        print(enzyme,sequence)

이게 \W. 제한효소 이름은 숫자와 알파벳만으로 되어 있으므로 저렇게 주고 찾으면 검색결과가 없는 게 정상이다. 

 

\A, \Z

문자열의 시작과 끝. ^과 $에 대응하지만 Multiline 옵션을 주더라도 얘는 문자열의 시작과 끝만 출력한다. 

 

*, *?

반복을 나타내는 문자. 0회 이상 반복이면 다 찾는다. 

 

for i in range(len(pokemon)):
    if re.search('김*추',pokemon[i]):
        print(pokemon[i])
김부추
김후추
김양상추
김배추
김2번척추씨

김과 추 사이에 뭐 들어가면 다 나온다. 

 

+, +?

얘는 한 번 이상 반복되면 다 나온다. 

 

for i in range(len(df)):
    enzyme = df['Enzyme'][i]
    sequence = df['sequence'][i]
    if re.search('^Ca+',enzyme):
        print(enzyme,sequence)
Cac8I GCNNGC
CaiI CAGNNNCTG
CauI GGWCC
CauII CCSGG

C로 시작하면서 a가 한 번 이상 들어가는 제한효소를 출력한다. 

 

?

for i in range(len(df)):
    enzyme = df['Enzyme'][i]
    sequence = df['sequence'][i]
    if re.search('^Ca?',enzyme):
        print(enzyme,sequence)
Cac8I GCNNGC
CaiI CAGNNNCTG
CauI GGWCC
CauII CCSGG
CbrI CCWGG
CcuI GGNCC
CelII GCTNAGC
CfrI YGGCCR
Cfr10I RCCGGY
Cfr13I GGNCC
CfrBI CCWWGG
CjeI CCANNNNNNGT
CjePI CCANNNNNNNTC
CpoI CGGWCCG
CspI CGGWCCG
CspCI CAANNNNNGTGG
Csp68KI GGWCC
CstMI AAGGAG
CthII CCWGG
CviBI GANTC
CviJI RGCY
CviTI RGCY
CvnI CCTNAGG

0회 or 1회 이상 반복. ...이럴거면 그냥 C로 시작하는 거 뽑고 말지... 

 

{ }

중괄호를 주면 반복 횟수를 지정할 수 있다. 

 

for i in range(len(pokemon)):
    if re.search('김.{1}추',pokemon[i]):
        print(pokemon[i])

아무거나 1회 반복

 

for i in range(len(pokemon)):
    if re.search('김.{1,3}추',pokemon[i]):
        print(pokemon[i])

아무거나 1~3회 반복

 

for i in range(len(df)):
    enzyme = df['Enzyme'][i]
    sequence = df['sequence'][i]
    if re.search('[GATC]{3}N{3}[GATC]',sequence):
        print(enzyme,sequence)
AdeI CACNNNGTG
AlwNI CAGNNNCTG
AspI GACNNNGTC
AtsI GACNNNGTC
BstZ316I CACNNNGTG
CaiI CAGNNNCTG
DraIII CACNNNGTG
PflFI GACNNNGTC
PsyI GACNNNGTC
TelI GACNNNGTC
Tth111I GACNNNGTC

GATC 중 아무거나 3개 반복되고 N이 3개 온 다음 GATC가 오는 패턴

Lv. 35 라이츄

Lv. 35 라이츄

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

Cutter 기능 추가: 정규식 도입

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

Finder는 도입하려면 좀 걸립니다... 얘는 아예 정규식+찾아바꾸기가 필요한거라...... 


정규식 도입

import pandas as pd
import re
from datetime import datetime
enzyme_table = pd.read_csv('/home/koreanraichu/restriction.csv')
enzyme_table2 = pd.read_csv('/home/koreanraichu/restriction_RE.csv')
# 정규식 도입을 위해... 어쩔 수 없이 합쳤음... 
enzyme_table = pd.concat([enzyme_table,enzyme_table2])
enzyme_table = enzyme_table.sort_values('Enzyme')
enzyme_table.reset_index(inplace=True)
# 합쳤다... 
print(enzyme_table)

뭐가 좀 많은데, RE 들어가는 csv파일이 정규식 처리가 필요한 효소들. 인식 시퀀스에 N, S, B같은 게 있는 효소들이다. 정규식 없이 find를 쓰면 못 찾기때문에 뺐다. 

 

class RE_treatment:
    def RE_wildcard(self,before_seq):
        self.before_seq = before_seq
        before_seq = before_seq.replace("N",".")
        return before_seq
    # Wildcard: 시퀀스 데이터에 N이 있을 경우 Wildcard로 바꾼다. 
    def RE_or(self,before_seq):
        self.before_seq = before_seq
        if "B" in before_seq:
            before_seq = before_seq.replace("B","[CGT]")
        elif "D" in before_seq:
            before_seq = before_seq.replace("D","[AGT]")
        elif "H" in before_seq:
            before_seq = before_seq.replace("H","[ACT]")
        elif "K" in before_seq:
            before_seq = before_seq.replace("K","[GT]")
        elif "M" in before_seq:
            before_seq = before_seq.replace("M","[AC]")
        elif "R" in before_seq:
            before_seq = before_seq.replace("R","[AG]")
        elif "S" in before_seq:
            before_seq = before_seq.replace("S","[CG]")
        elif "V" in before_seq:
            before_seq = before_seq.replace("V","[ACG]")
        elif "W" in before_seq:
            before_seq = before_seq.replace("W","[AT]")
        elif "Y" in before_seq:
            before_seq = before_seq.replace("Y","[CT]")
        return before_seq
    # Or: 시퀀스 데이터에 N 말고 ATGC 말고 다른 알파벳이 있을 경우, 해당하는 정규식 문법으로 바꾼다.

클래스. 대충 쿠키틀 해당 클래스는 N, D, B와 같은 알파벳들을 정규식 처리 하는 코드를 담고 있다. 

 

def convert (a):
    RE = RE_treatment()
    while True:
        if "N" in res_find:
            res_find_after = RE.RE_wildcard(res_find)
        elif "B" in res_find or "D" in res_find or "H" in res_find or "K" in res_find or "M" in res_find or "R" in res_find or "S" in res_find or "V" in res_find or "W" in res_find or "Y" in res_find: 
            res_find_after = RE.RE_or(res_find)
        else: 
            break
        return res_find_after

무식하게 조건문 때려박은 if문... 저 While True가 없으면 GCDGHC처럼 알파벳이 여러글자일 때에 대한 처리가 안된다. (N은 아예 일괄적으로 wildcard화 함)

 

if "N" in res_find or "B" in res_find or "D" in res_find or "H" in res_find or "K" in res_find or "M" in res_find or "R" in res_find or "S" in res_find:
    res_find_after = str(convert(res_find))
else: 
    res_find_after = res_find
# 정규식 처리(문자가 두 개 이상일때에 대한 처리가 필요함)
Findall = re.findall(res_find_after,sequence)
if Findall: 
    count += 1
    site_count = len(Findall)
    if site_count == 1:
    once_cut_list.append(enzyme)
elif site_count == 2: 
    two_cut_list.append(enzyme)
else: 
    multi_cut_list.append(enzyme)
res_loc_list = ', '.join(res_loc_list)
f.write("{0}: {1} {2},{3} times cut. Where(bp): {4} \n".format(enzyme,res_find,feature,site_count,res_loc_list))

(그래서 대충 문제의 코드)

 

어디 자르는지 세 주는 기능

얘는 쉽다. 

 

def cut_func (a,b):
    global res_loc_list
    locs = re.finditer(a,b)
    for i in locs:
        loc = i.start()
        res_loc_list.append(str(loc))
    return res_loc_list
# 여기가 위치 관련 함수입니다.

finditer()로 다 찾은 다음, 해당 레코드에서 start(시작 지점)을 리스트화하면 된다.

결과 

이제 Finder에 도입한 다음 FASTA까지 하면 어지간한건 다 된다. 

Lv. 35 라이츄

Lv. 35 라이츄

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

방명록