레이블이 파이썬인 게시물을 표시합니다. 모든 게시물 표시
레이블이 파이썬인 게시물을 표시합니다. 모든 게시물 표시

2023년 9월 6일 수요일

NumPy Broadcasting


Broadcasting은 NumPy 라이브러리에서 다른 형태(shape)의 배열 간에도 산술 연산이 가능하게 해주는 기능입니다. 일반적으로, NumPy에서 배열 간 연산은 배열의 형태가 동일해야 하는데, Broadcasting은 이러한 제약을 완화해줍니다.

기본 규칙

Broadcasting은 다음과 같은 규칙을 따릅니다:

  1. 두 배열의 차원 수가 다르면, 더 작은 차원을 가진 배열의 형태(shape) 앞에 1을 추가합니다.
  2. 두 배열이 어떤 차원에서도 크기가 동일하거나, 한쪽이 1이라면 호환되는 것으로 간주됩니다.
  3. 어느 한 차원에서도 크기가 일치하지 않고 1도 아니라면 오류가 발생합니다.

이것 말은 어려운데 실제 동작하는것보면 쉽게 이해할 수 있습니다.

예제

예제 1: 벡터와 스칼라 덧셈

import numpy as np

a = np.array([1, 2, 3])
b = 2

result = a + b
# result: array([3, 4, 5])

예제 2: 2차원 배열과 1차원 배열 덧셈

A = np.array([[1, 2], [3, 4], [5, 6]])
B = np.array([1, 2])

result = A + B
# result: array([[2, 4], [4, 6], [6, 8]])

장점과 단점

장점

  • 간결성: 더 적은 메모리와 코드로 같은 연산을 수행할 수 있습니다.
  • 성능: Broadcasting을 이용한 연산은 내부적으로 최적화되어 있어 빠른 연산 속도를 제공합니다.

단점

  • 복잡성: Broadcasting 규칙을 이해하지 못하면 예상치 못한 결과를 얻을 수 있습니다.
  • 디버깅: 문제가 발생했을 때, 디버깅이 상대적으로 어렵습니다.

결론

NumPy의 Broadcasting 기능은 배열 연산을 더 간편하고 빠르게 해주지만, 사용에 앞서 해당 메커니즘을 잘 이해하는 것이 중요합니다. 잘 활용하면 다양한 수학적 문제와 데이터 분석 작업에서 큰 이점을 볼 수 있습니다.

2022년 11월 28일 월요일

파이썬 딕셔너리 merge (|) 연산자 추가 (3.9이상)

유니온 연산자(|) 


딕셔너리에 | (유니온 연산자)를 사용할 수 있습니다. 값을 병합합니다. 기존의 값이 있으면 새 값으로 업데이트 합니다 x.update(y) 의 간단한 버전입니다.
x = {"k1": "v1x", "k2": "v2x"}
y = {"k2": "v2y", "k3": "v3y"}
print (x | y)
# {'k1': 'v1x', 'k2': 'v2y', 'k3': 'v3y'}
print (y | x)
# {'k1': 'v1x', 'k2': 'v2x', 'k3': 'v3y'}
여기서 주의 깊게 볼 건 k2값이 순서에 따라 다른 부분 입니다. 뒤에 있는 값이 Update되는 값이라 최신이 됩니다.

이 기능은 파이썬 3.9에서부터 지원합니다. 

2022년 11월 2일 수요일

파이썬 2차원 배열 생성 및 초기화

파이썬에서 2차원 배열이 필요할 때가 있습니다. 그런데 2차원 배열은 리스트 컴프리헨션등으로 쉽게 만들어 낼 수가 있습니다. 다만, 여기서 하나 주의할 점이 있어서 그 부분만 집고 넘어가려고 합니다.

먼저, 2차원 배열은 화면에 그냥 뿌리면 보기 불편하니, 아래와 같이 2차원 배열을 뿌리는 함수를 먼저 만듭니다.

def print_2d(a):
    for row in a:
        for c in row:
            print (c,end= ' ')
        print ('')

2중 for문으로 2중 리스트 선언

ROW, COL = 4, 5
arr = [[0 for c in range(COL)] for row in range(ROW)]
# 5x4 리스트를 생성합니다.  = (4열 5행) 
arr[2][3] = 9 # (3, 2)에 값을 변경합니다. 
print_2d(arr)
'''
0 0 0 0 0 
0 0 0 0 0 
0 0 0 9 0 
0 0 0 0 0 
'''

2차원 배열 access

# arr[row][col]
arr[2][3] = 9 

위와 같이 row가 앞쪽에 위치합니다. 이 부분도 은근히 헷갈릴 수 있으니 주의합시다.

*연산자와 for문으로 리스트 선언

arr = [[0]*5 for i in range(4)]
arr[2][3] = 9
print_2d(arr)
'''
0 0 0 0 0 
0 0 0 0 0 
0 0 0 9 0 
0 0 0 0 0 
'''

연산자 *로 2중 리스트 선언

arr = [[0]*5 ]*4
arr[2][3] = 9
print_2d(arr)
'''
0 0 0 9 0 
0 0 0 9 0 
0 0 0 9 0 
0 0 0 9 0 
'''

이 방법은 주의해야합니다. 위의 두 방법 말고 이 방법으로 배열을 선언하게 되면, row를 새로 생성하는것이 아니라. 단순히 요소를 복사하게 되는 얕은복사 (shallow copy)가 발생합니다. 즉, row의 첫번째 값의 링크로 만들어진 것이라 저런식으로 만들게 되면 어떤 값이든 바꿀때 마다 값이 같이 변경됩니다. 위 예제에서도 (3,2)를 변경했는데 모든 row가 같이 바뀐것을 확인할 수 가 있습니다.

이러한 방식으로 선언 뒤에, 값을 변경하게되면 다른 원소들도 값이 변경되는 현상이 발생하게 되므로 이를 인지하고, 후에 대입연산자를 통해 값을 변경하지 않는 경우에만 사용하는것이 유리합니다. 그런데 위 방법은 그냥 쓰지 않는것을 추천합니다

a = [0]*10
a[3] = 8
print(a)
# [0, 0, 0, 8, 0, 0, 0, 0, 0, 0]

물론 1차원 배열을 생성할 때는 이런 shallow copy문제는 없습니다.

2022년 10월 26일 수요일

파이썬 textwrap (indent, 정렬, 줄바꿈)

 이 textwrap 모듈은 텍스트를 핸들링할때 indentation을 넣거나 빼거나, 글자수를 터미널 너비에 맞춘다거나 할때 유용합니다. 즉, pretty-print가 필요한 경우, 텍스트를 핸들링할때 유용합니다. 많은 텍스트 편집기 및 워드 프로세서에서 볼 수 있는 단락 줄 바꿈 또는 채우기 기능과 유사한 프로그래밍 기능을 제공합니다.

Filling Paragraphs

fill 함수에 대해 알아봅니다 fill() 함수는 텍스트를 width에 맞게 잘라주는 역할을 합니다.

# 실제 함수원형은 좀더 길지만, 아래 형태로 확인합니다
textwrap.fill(text: str, width: int) -> str 
import textwrap

text = '''
    I have two sisters who have made their careers in engineering. My first sister has
    a doctorate in civil engineering. She works in Australia designing mine tunnels for
    a raw materials company. My second sister earned a master's degree in electrical
    engineering. She works in the United States designing communication equipment.
    In summary, my two sisters both have graduate degrees in engineering and have
    careers in engineering.
'''

print (textwrap.fill(text,width=50))
'''
 I have two sisters who have made their careers in
engineering. My first sister has a doctorate in
civil engineering. She works in Australia
designing mine tunnels for a raw materials
company. My second sister earned a master's degree
in electrical engineering. She works in the United
States designing communication equipment. In
summary, my two sisters both have graduate degrees
in engineering and have careers in engineering.
'''

이제 텍스트가 왼쪽 정렬되지만 첫 번째 줄은 들여쓰기를 유지하고 각 후속 줄의 앞부터 공백이 단락에 포함됩니다.

textwrap 모듈은 예쁜 인쇄가 필요한 상황에서 출력할 텍스트의 형식을 지정하는 데 사용할 수 있습니다. 프로그래밍 방식을 제공합니다. 많은 텍스트 편집기에서 볼 수 있는 단락 줄 바꿈 또는 채우기 기능과 유사한 기능입니다.

Indentation 제거

이전 예제에는 출력에 포함된 탭과 추가 공백이 포함되어 있으므로 형식이 매우 명확하지 않습니다. 샘플 텍스트의 모든 줄에서 공통 공백 접두사를 제거하면 더 나은 결과를 얻을 수 있으며 코드 서식 자체를 제거하면서 Python 코드에서 직접 독스트링 또는 포함된 여러 줄 문자열을 사용할 수 있습니다. 샘플 문자열에는 이 기능을 설명하기 위해 도입된 인위적인 들여쓰기 수준이 있습니다. dedent를 사용하면 공백을 제거해 줍니다.

'''
I have two sisters who have made their careers in engineering. My first sister has
a doctorate in civil engineering. She works in Australia designing mine tunnels for
a raw materials company. My second sister earned a master's degree in electrical
engineering. She works in the United States designing communication equipment.
In summary, my two sisters both have graduate degrees in engineering and have
careers in engineering.
'''

아래 예제도 참고 합니다. indent가 들쭉날쭉 한 경우에도 이 공백을 댕겨줍니다. 다만, 실제 paragraph상의 indent를 제거하지 않습니다.

text2= '''
        I have two sisters who have made their careers in engineering. My first sister has
    a doctorate in civil engineering. She works in Australia designing mine tunnels for
    a raw materials company. My second sister earned a master's degree in electrical
    engineering. She works in the United States designing communication equipment.
        In summary, my two sisters both have graduate degrees in engineering and have
    careers in engineering.
'''

print (textwrap.dedent(text2))

'''
    I have two sisters who have made their careers in engineering. My first sister has
a doctorate in civil engineering. She works in Australia designing mine tunnels for
a raw materials company. My second sister earned a master's degree in electrical
engineering. She works in the United States designing communication equipment.
    In summary, my two sisters both have graduate degrees in engineering and have
careers in engineering.
'''

Dedent 와 Fill 함수 조합

다음은 dedent된 텍스트를 fill로 맞추어 봅니다. 위의 Text2 예제를 그대로 씁니다. dedent로 공백을 걷어내고, strip() 으로 좌우 여백을 완전히 잘라줍니다. 그리고 fill을 사용하면 width에 맞게 다시 text가 정렬이 됩니다.

text3= textwrap.dedent(text2).strip()
text4= textwrap.fill(text3,width=60)
print (text4)
'''
I have two sisters who have made their careers in
engineering. My first sister has a doctorate in civil
engineering. She works in Australia designing mine tunnels
for a raw materials company. My second sister earned a
master's degree in electrical engineering. She works in the
United States designing communication equipment.     In
summary, my two sisters both have graduate degrees in
engineering and have careers in engineering.
'''

Indents

때로는 문장 전체에 앞에 공백등을 넣어야 할때가 있습니다. 원래 문장에 4칸의 공백을 넣어봅니다.

text5='''
I have two sisters who have made their careers in
engineering. My first sister has a doctorate in civil
engineering. She works in Australia designing mine tunnels
for a raw materials company. My second sister earned a
master's degree in electrical engineering. She works in the
United States designing communication equipment.     In
summary, my two sisters both have graduate degrees in
engineering and have careers in engineering.
'''
print (textwrap.indent(text5,' '*4))

'''
    I have two sisters who have made their careers in
    engineering. My first sister has a doctorate in civil
    engineering. She works in Australia designing mine tunnels
    for a raw materials company. My second sister earned a
    master's degree in electrical engineering. She works in the
    United States designing communication equipment.     In
    summary, my two sisters both have graduate degrees in
    engineering and have careers in engineering.
'''

위와 같이 indent가 잘 삽입되었습니다.

이상으로 textwrap이 잘 동작 하는것을 확인해보았습니다. 이 textwrap은 종종 텍스트를 화면에 안잘리고 pretty-print하는 용도로 사용합니다.

2022년 10월 21일 금요일

파이썬 zfill 문자열 앞에 0 채우기 (이진수 만들기)

이 파이썬의 zfill함수는 이진수를 만들때 유용합니다. 뿐만 아니라, 전화번호나 날짜등을 표기할때도 유용합니다. 이번에는 주로 바이너리를 표현하는 방법에 관련해서적어 보려고 합니다.

먼저 8을 이진수로 변경해봅니다.

print (bin(8))
# 0b1000

앞의 0b가 거슬립니다. 문자열이니 2번째 다음부터 가져오면 이진수만 떼어내 봅시다.

print (bin(8)[2:])
# 1000

이번엔 8이외에 여러 숫자들을 이진수로 바꾸어 봅니다.


print (bin(0)[2:])
print (bin(1)[2:])
print (bin(2)[2:])
print (bin(3)[2:])
print (bin(6)[2:])
print (bin(7)[2:])
print (bin(8)[2:])

# 0
# 1
# 10
# 11
# 110
# 111
# 1000

이진수가 만들어지지만, 뭔가 좀 비뚤빼뚤합니다. 이때 자리를 맞추기 위해서 zfill함수를 사용합니다.

print (bin(0)[2:].zfill(4))
print (bin(1)[2:].zfill(4))
print (bin(2)[2:].zfill(4))
print (bin(3)[2:].zfill(4))
print (bin(6)[2:].zfill(4))
print (bin(7)[2:].zfill(4))
print (bin(8)[2:].zfill(4))

# 0000
# 0001
# 0010
# 0011
# 0110
# 0111
# 1000

인제 뭔가 자리수가 맞는것 같습니다. 이렇게 표현하는 것이 뭔가 줄이 맞으니, 가독성면에서도 좋습니다 이 zfill 함수는 위와 같이 N자리 보다 작은 스트링을 앞쪽에 0을 붙여서 채웁니다.

이 방법은 위와 같이 파이썬으로 이진수 표현할 때 유용합니다. 

2022년 10월 20일 목요일

파이썬 collections Counter

Collection의 Counter 함수는 array나 list에 해당 값이 얼마나 나왔는지 세는 함수입니다.

이 Counter object는 사실 dictionary를 inherit 한것이라,, dictionary형태를 지니고 있습니다

아래는 예제입니다.

from collections import Counter
sample = Counter([1,2,3,4,2,3,4,1,2,3])
print (sample[4])  # 2

위 결과는 4의 개수를 센 값이 나옵니다.

Counter는 실제 excel같은데서 많이들 사용하는 함수와 같은 유형이라, 생각보다 유용한 경우가 많이 있습니다.

counter 함수를 사용해 리스트의 개수세기

collections.Counter(a) : a에서 요소들의 개수를 세어, 딕셔너리 형태로 반환합니다. {문자 : 개수} 형태

import collections
b = [1,3,4,3,2,3,5,1,2,3,2,3,9]
a = [1,2,3,4,3,2,2,1,5,3,1,3,4,2,3]
print(collections.Counter(a) , collections.Counter(b))

# Counter({3: 5, 2: 4, 1: 3, 4: 2, 5: 1}) Counter({3: 5, 2: 3, 1: 2, 4: 1, 5: 1, 9: 1})

counter - 연산

counter 함수로 구한 딕셔너리의 값(value)끼리 연산이 가능합니다. 연산은 + , - , &(교집합), |(합집합) 네가지가 가능합니다. 서로 빼기 연산을 했을때 , 음수 값이 나오지는 않습니다. a list의 2, 3번이 나오지 않습니다

import collections
a = [1,1,1,1,2,3,1,1]
b = [1,1,2,2,2,2,3,3,3]

print(collections.Counter(a) - collections.Counter(b))
print(collections.Counter(a) + collections.Counter(b))
print(collections.Counter(a) & collections.Counter(b))
print(collections.Counter(a) | collections.Counter(b))

# Counter({1: 4})
# Counter({1: 8, 2: 5, 3: 4})
# Counter({1: 2, 2: 1, 3: 1})
# Counter({1: 6, 2: 4, 3: 3})

most_common() 함수 - 최빈값 구하기

most_common([n]) : 많이나오는 순서대로 상위부터 n개까지를 출력 (리스트에 담긴 튜플형태로)

import collections
a  = [1,1,1,2,3,2,3,1,4,2,2,2,45,9]

print(collections.Counter(a).most_common(3))
 
# [(2, 5), (1, 4), (3, 2)]

elements() : 모든 element의 list를 출력

import collections
a  = [1,1,1,2,3,2,3,1,4,2,2,2,45,9]

print(list(collections.Counter(a).elements()))
 
# [1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 4, 45, 9]

이상으로 collections의 Counter 메소드들을 정리해보았습니다.




2022년 10월 19일 수요일

파이썬 정규식, Greedy Non Greedy탐색(최소일치/최대일치)

 이번엔 파이썬의 정규식(RegEx)중 Greedy match/Non-Greedy match부분을 설명합니다.

아래와 같은 예제에서 첫번째 괄호만 매치를 시키자고 하고합니다.

text = '(Machester 10) (London 20) (Seoul 30) (Tokyo 40)'

그렇지만, 실제로 아래와 같은 예제를 보면, 첫번째 괄호만 매치되는 게 아니라 마지막 괄호까지 전부 매치가 됩니다.

(.*) - Greedy match

(Manchester 10) (London  20) (Seoul 30) (Tokyo 40)

(.*?) - Non Greedy match (Manchester 10) (London  20) (Seoul 30) (Tokyo 40)

이것은 기본적으로 정규식은 Greedy match (최대한 많이 매치)를 하기 때문인데, 이렇게 되면 원래 의도와는 다른 결과가 나올 수 있습니다.

그래서 .* 뒤에 ?를 붙여서 .*? 과 같이 표현합니다. 그러면, 이 탐색자가 가장 많이 매치되는 경우를 찾아주는 것이 아니라 가장 적게 매치되는 경우를 찾아줍니다.

text = '(Machester 10) (London 20) (Seoul 30) (Tokyo 40)'
p = re.compile(r'(\(.*\))')
if m:= p.search(text): print (m.groups()) 
# ('(Machester 10) (London 20) (Seoul 30) (Tokyo 40)',)

p = re.compile(r'(\(.*?\))')
if m:= p.search(text): print (m.groups()) 
# ('(Machester 10)',)

이런 예는 종종 볼수 있습니다. 이것 말고도 HTML, XML match시킬때도 마찬가지 입니다. 또, C-style 주석도 이런 경우 종종 볼수 있습니다. /* ...  */ 와 같이 주석처리를 지우려고 하는데 , 텍스트 파일 전체가 지워지는 경우, 이 그리디매치가 적용이 되어서 그런것입니다.

가장 가까운 괄호와 매치시키고 싶은데, 반복자가 최대한 많이 매치시키려 하기 때문에, 이런 부분의 차이를 알고 있다면 정규식 쓰는데 좀더 활용도를 높일 수가 있습니다.