[AI_PY4ML] Pythonic Code

JJangnaa·2023년 8월 15일
0

1. Overview

  • 학습목표
    - Pythonic Code는 간단하게, 다른 사람의 코드를 잘 이해하기 위해서 파이썬 특유의 문법을 활용하여 효율적으로 코드를 표현하는 기법을 말한다.
    - Pythonic Code 를 작성하는 방법과 Matrices 와 Vector 의 연산을 Pythonic Code 로 구현하는 방법을 배운다.

1) 여러 단어를 하나로 붙일 때

colors = ['red', 'blue', 'green', 'yellow']
result = ''
for s in colors:
	result += s
colors = ['red', 'blue', 'green', 'yellow']
result = ''.join(colors)

2) Pythonic Code

  • 파이썬 스타일의 코딩 기법
  • 파이썬 특유의 문법을 활용하여 효율적으로 코드를 표현함
  • 고급 코드를 작성 할 수록 더 많이 필요해짐

- Split & Join
- List Comprehension
- Enumerate & Zip

3) Why Python Code?

  • 남 코드에 대한 이해도
    -- : 많은 개발자들이 python 스타일로 코딩함

  • 효율
    -- : 단순 for loop append 보다 list가 조금 더 빠르고, 익숙해지면 코드도 짧아짐
    -- ↪ numpy가 훨씬 빠름



2. Split & Join

  • 학습목표: Split & Join 을 사용하여 String Type 의 값을 List 형태로 변환하고, List Type 의 값을 String Type 의 값으로 변환하는 Python Code 작성법을 알아본다.
  • 핵심단어
    - Split
    - Join
    - String
    - List
    - Unpacking

1) Split 함수

--String Type의 값을 나눠서 List 형태로 변환
-- ↪ 많이 쓰이는 경우: 뉴스와 같은 데이터에 특정 단어가 몇번 등장하는지 등

items = 'zero one two three'.split()
	## ['zero', 'one', 'two', 'three']
  
example = 'python,query,javascript'
example.split(',')
	## ['python', 'query', 'javascript']
    
a, b, c = example.split(',')
	## a is 'python', b is 'query', c is 'javascript' : Unpacking
    
example = 'cs50.gachon.edu'
subdomain, domain, tld = example.split('.')
	## subdomain is 'cs50', domain is 'gachon', tld is 'edu'

2) Join 함수

-- String List를 합쳐 하나의 String 으로 반환할 때 사용

colors = ['red', 'blue', 'green', 'yellow']
''.join(colors)
	## 'redbluegreenyellow'
' '.join(colors)
	## 'red blue green yellow'
', '.join(colors)
	## 'red, blue, green, yellow'
'-'.join(colors)
	## 'red-blue-green-yellow'


3. List Comprehension

  • 학습목표: 파이썬에서 가장 많이 사용되는 기법 중 하나인 List Comprehension 을 사용하여 Pythonic Code 를 작성하는 방법을 알아본다.
  • 핵심단어
    - List Comprehension
    - Nested For loop

1) 정의

  • 기존 List 사용하여 간단히 다른 List를 만드는 기법

  • 포괄적인 List, 포함되는 리스트라는 의미로 사용됨

  • 파이썬에서 가장 많이 사용되는 기법 중 하나

  • 일반적으로 for + append 보다 속도가 빠름

2) 예시 (1)

result = []
for i in range(10):
	result.append(i)

	## [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[i for i in range(10)]	# list comprehensions
	## [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[i for i in range(10) if i % 2 == 0]	# list comprehensions & filter
	## [0, 2, 4, 6, 8]

3) 예시 (2)

word_1 = "Hello"
word_2 = "World"

[i+j for i in word_1 for j in word_2]	# Nested For loop

## ['HW', 'Ho', 'Hr', 'Hl', 'Hd', 'eW', 'eo', ...]

4) 예시 (3)

case_1 = ["A", "B", "C"]
case_2 = ["D", "E", "F"]

[i+j for i in case_1 for j in case_2]

result = [i+j for i in case_1 for j in case_2 if not(i==j)]

result.sort()

5) 예시 (4)

words = 'The quick brown fox jumps over the lazy dog'.split()

stuff = [[w.upper(), w.lower(), len(w)] for w in words]
# list의 값 elements 들을 대문자, 소문자, 길이로 변환하여 two dimensional list로 변환

for i in stuff:
	print(i)

6) Two dimensional vs One dimentional

case_1 = ["A", "B", "C"]
case_2 = ["D", "E", "F"]

[a+b for a in case_1 for b in case_2]
# ['AD', 'AE', 'AF', 'BD', 'BE', 'BF', 'CD', 'CE', 'CF']

[[a+b for a in case_1] for b in case_2]		# for b in case_2 부분이 먼저 고정 됨
# [['AD', 'BD', 'CD'], ['BD', 'BE', 'BF'], ['CD', 'CE', 'CF']]


4. Enumerate & Zip

  • 학습목표: 리스트의 값을 추출할 때 함께 인덱스를 추출할 수 있는 방법으로 이용되는 enumerate 와 두 개 이상의 list 값을 병렬적으로 추출할 수 있는 zip 모듈을 사용하여 pythonic code 를 작성하는 방법을 알아본다
  • 핵심단어
    - Zip
    - Enumerate

1) Enumerate

-- List 의 element 를 추출할 때 번호를 붙여서 추출

for i, v in enumerate(['tic', 'tac', 'toc']):
	print(i, v)
## 0 tic / 1 tac / 2 toc

mylist = ['a', 'b', 'c', 'd']
list(enumerate(mylist))		# list의 index 와 value 를 unpacking 하여 list로 저장
## [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]

{i:j for i, j in enumerate("Gachon University in an academic institute located in South Kores.".split())}
# 문장을 list로 만들고 그 list의 index 와 value 를 unpacking 하여 dict 로 저장

2) Zip

-- 두 개의 list 의 값을 병렬적으로 추출함

alist = ['a1', 'a2', 'a3']
blist = ['b1', 'b2', 'b3']

for a, b in zip(alist, blist):	# 병렬적으로 값을 추출
	print(a, b)
    
## a1 b1 / a2 b2 / a3 b3

a, b, c = zip((1, 2, 3), (10, 20, 30), (100, 200, 300))	# 각 tuple 의 같은 index 끼리 묶음
## ((1, 10, 100), (2, 20, 200), (3, 30, 300))

[sum(x) for x in zip((1, 2, 3), (10, 20, 30), (100, 200, 300))]	# list comprehension 이랑 같이 사용해보기
## [111, 222, 333]

3) Enumerate & Zip

alist = ['a1', 'a2', 'a3']
blist = ['b1', 'b2', 'b3']

for i, (a, b) in enumerate(zip(alist, blist)):
	print(i, a, b)	# index alist[index] blist[index]

## 0 a1 b1 / 1 a2 b2 / 2 a3 b3


5. Lambda & MapReduce

  • 학습목표: 함수처럼 사용가능한 익명함수인 Lambda, Sequence 자로형의 데이터에서 함수를 적용하는 방법인 Map Function 과 Reduce Function 에 대해서 여러 예제 코드를 이용해 실습하면서 Pythonic Code 를 작성하는 방법에 대해 공부합니다.
  • 핵심단어
    - Lambda
    - Map Function
    - Reduce Function

1) Lambda

  • 함수 이름 없이 함수처럼 쓸 수 있는 익명함수로 수학의 람다 대수에서 유래함
  • map 함수와 함께 쓰면 더 효율적임
General functionLambda function
def f(x,y) : return x+yf = lambda x, y: x + y
f = lambda x, y: x+ y
print(f(1, 4))	# 5

f = lambda x: x ** 2
print(f(3))	# 9

f = lambda x: x / 2
print(f(3))	# 1.5

print((lambda x: x + 1)(5))	# 6

2) Map

  • Sequence 자료형 각 elemnet 에 동일한 function 을 적용함
    map(function_name, list_data)
ex = [1, 2, 3, 4, 5]
f = lambda x: x ** 2
print(list(map(f, ex)))	## [1, 4, 9, 16, 25]

f = lambda x, y: x+ y
print(list(map(f, ex, ex)))	## [2, 4, 6, 8, 10]

list(map(
	lambda x: x ** 2 if x % 2 == 0 else x,
    ex))
# lambda 에 filter 가능, else 는 필수로 넣어야 함
## [1, 4, 3, 16, 5]

3) Reduce

-- map function 과 달리 list 에 똑같은 함수를 적용해서 통합 (map과 같이 쓰는 경우가 많음, pandas 사용시 map과 함께 유용하게 쓰임)

from functools import reduce
print(reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]))	## 15

## x = 1, y = 2
## x = 3, y = 3
## x = 6, y = 4
## x = 10, y = 5
def factorial(n):
	return reduce(
    	lambda x, y: x*y, range(1, n+1))

factorial(5)	## 120

⨁ Summary

  • Lambda, map, reduce 는 간단한 코드로 다양한 기능을 제공
  • 그러나 코드의 직관성이 떨어져서 lambda 나 reduce 는 python3 에서 사용을 권장하지 않음
  • Legacy library 나 다양한 머신러닝 코드에서 여전히 사용중


6. Asterisk

  • 학습목표: 단순 곱셈, 제곱연산, 가변인자 활용 등 여러 부분에서 다양하게 사용되는 Asterisk(*) 의 사용법을 여러 예제 코드를 직접 실습하며 공부한다.
  • 핵심단어: Asterisk

1) Asterisk

-- 흔이 알고 있는 * 를 의미하며, '단순곱셈' '제곱연산' '가변인자활용' 등 다양하게 사용됨

*args**kargs
def asterisk_test(a, *args)
: 함수 만들 때 몇 개의 인자를 받을지 정할 수 없을 때 여러 개 값을 한번에 받을 수 있음
def asterisk_test(a, **kargs)
: 키워드 인자, dict type 이며, pandas matplotlib 등에 사용됨
def asterisk_test(a, *args):
	print(a, args)
    print(type(args))
    
asterisk_test(1, 2, 3, 4, 5, 6)
##	1 (2, 3, 4, 5, 6)
## <class 'tuple'>
def asterisk_test(a, **kargs):
	print(a, kargs)
    print(type(kargs))
    
asterisk_test(1, b=2, c=3, d=4, e=5, f=6)
## 1 {'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6}
## <class 'dict'>

2) Asterisk - unpacking a container

  • tuple, dict 등 자료형에 들어가 있는 값을 unpacking
  • 함수의 입력값, zip 등에 유용하게 사용 가능
def asterisk_test(a, *args):
	print(a, args)
    print(type(args))
asterisk_test(1, *(2, 3, 4, 5, 6))
## 1 (2, 3, 4, 5, 6)	/	<class 'tuple'>

def asterisk_test(a, args):
	print(a, *args)
    print(type(args))
asterisk_test(1, (2, 3, 4, 5, 6))
## 1 2 3 4 5 6	/	<class 'tuple'>
def asterisk_test(a, *args):
	print(a, args[0])
    print(type(args))
asterisk_test(1, (2, 3, 4, 5, 6))
## 1 (2, 3, 4, 5, 6)	/	<class 'tuple'>

def asterisk_test(a, *args):
	print(a, args)
    print(type(args))
asterisk_test(1, (2, 3, 4, 5, 6))
## 1 ((2, 3, 4, 5, 6), )	/	<class 'tuple'>
  • 예시
a, b, c = ([1, 2], [3, 4], [5, 6])
## a is [1, 2] / b is [3, 4] / c is [5, 6]

data = ([1, 2], [3, 4], [5, 6])
print(*data)
## [1, 2] [3, 4] [5, 6]

def asterisk_test(a, b, c, d):
	print(a, b, c, d)
data = {"b": 1, "c": 2, "d": 3}
asterisk_test(10, **data)
## asterisk_test(10, **data)

for data in zip(*([1, 2], [3, 4], [5, 6])):		## [1, 2] [3, 4] [5, 6]
	print(data)
## (1, 3, 5)
## (2, 4, 6)


7. Data Structure - Collections

  • 학습목표: tuple, dict 에 대한 확장 데이터 구조를 제공하는 Collections 안에 포함된 모듈을 이용하여 Data Structure 의 기본 개념을 이해하고 사용하는 방법을 알아본다.
  • 핵심단어
    - Collections
    - Data Structure
    - deque
    - Counter
    - orderdDict
    - defaultdict
    - namedtuple

1) Collections

  • List, Tuple Dict 에 대한 Python Built-in 확장 자료 구조 (모듈)
  • 편의성, 실행 효율 등을 사용자에게 제공함
  • 아래의 모듈이 존재함
from collections import deque
from collections import Counter
from collections import OrderedDict
from collections import defaultdict
from collections import namedtuple

2) deque

  • Stack 과 Queue 를 지원하는 모듈
  • List 에 비해 효율적인 자료 저장 방식을 지원함
from collections import deque

deque_list = deque()
for i in range(5):
	deque_list.append(i)
print(deque_list)	## [0, 1, 2, 3, 4]

deque_list.appendleft(10)
print(deque_list)	## [10, 0, 1, 2, 3, 4]
  • rotate, reverse 등 Linked List 의 특성을 지원함
  • 기존 list 형태의 함수를 모두 지원함
deque_list.rotate(2); print(deque_list)

deque_list.rotate(2); print(deque_list)

deque_list.extend([5, 6, 7]); print(deque_list)

deque_list.extendleft([5, 6, 7]); print(deque_list)

print(deque_list)
print(deque(reversed(deque_list)))
  • deque 는 기본 list 보다 효율적인 자료구조를 제공
  • 효율적 메모리 구조로 처리 속도 향상
### deque
from collections import deque
import time

start_time = time.clock()
deque_list = deque()
# Stack
for i in range(10000):
	for i in range(10000):
    	deque_list.append(i)
        deque_list.pop()
print(time.clock() - start_time, 'seconds')

### general list
import time
start_time = time.clock()
just_list = []
for i in range(10000):
	for i in range(10000):
    	just_list.append(i)
        just_list.pop()
print(time.clock() - start_time, 'seconds')

3) OrderedDict

(1) OrderdDict

  • Dict 와 달리, 데이터를 입력한 순서대로 dict 를 반환함
d = {}
d['x'] = 100; d['y'] = 200; d['z'] = 300; d['l'] = 500

for k, v in d.items():
	print(k, v)

## l 500  /  x 100  /  y 200  /  z 300
from collections import OrderedDict

d = OrderedDict()
d['x'] = 100; d['y'] = 200; d['z'] = 300; d['l'] = 500

for k, v in d.items():
	print(k, v)
    
## x 100  /  y 200  /  z 300  /  l 500
  • Dict type 의 값을, value 또는 key 값으로 정렬할 때 사용 가능
for k, v in OrderedDict(sorted(d.items(), key=lambda t: t[0])).items():
	print(k,v)

## l 500  /  x 100  /  y 200  /  z 300
for k, v in OrderedDict(sorted(d.items(), key=lambda t: t[1])).items():
	print(k,v)

## x 100  /  y 200  /  z 300  /  l 500

(2) defaultdict

-- Dict type 의 값에 기본 값을 지정, 신규 값 생성 시 사용하는 방법

d = dict()
print(d["first"])	## KeyError
from collections import defaultdict
d = defaultdict(object)	# Default dictionary 를 생성
d = defaultdict(lambda: 0)	# Default 값을 0으로 설정함
print(d["first"])	## 0

예시

from collections import OrderdDict
from collections import defaultdict

word_count = defaultdict(object)	# Default dictionary 를 생성
word_count = defaultdict(lambda: 0)	# Default 값을 0으로 설정함

for word in text:
	word_count[word] += 1
for i, v in OrderedDict(sorted(word_count.items(), key=lambda t: t[1],
								reverse=Treu)).items():
	print(i, v)

## a 12  /  to 10  /  and 9  /  the 0  /  press 8  /  release 8   /  that 7

4) Counter

(1) counter

-Sequence type 의 data element 들의 갯수를 dict 형태로 반환

from collections import Counter

c = Counter()	# a new, empty counter
c = Counter('gallahad')	# a new counter from an iterable

print(c)	## Counter({'a': 3, 'l': 2, 'g': 1, 'd': 1, 'h': 1})
  • Dict type, keyword parameter 등도 모두 처리 가능
c = Counter({'red': 4, 'blue': 2})	# a new counter from a mapping

print(c)	# Counter({'red': 4, 'blue': 2})
print(list(c.elements()))	# ['blue', blue', 'red', 'red', 'red', 'red']

c = Counter({cats=4, dogs=8})	# a new counter from keyword args

print(c)	# Counter({'dogs': 8, 'cats': 4})
print(list(c.elements()))	# ['dogs', 'dogs', 'dogs', 'dogs', 'dogs', 'dogs','dogs','dogs', 'cats', 'cats', 'cats', 'cats']

(2) namedtuple

-- Tuple 형태로 Data 구조체를 저장하는 방법으로 저장되는 data 의 variable 을 사전에 지정해서 저장함
↪ C의 struct 와 비슷

from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(11, y=22)
print(p[0] + p[1])

x, y = p
print(x, y)
print(p.x + p.y)
print(Point(x=11, y=22))
profile
귀여운게 좋아

0개의 댓글