ai tech

ai tech 3일차

완달프 2021. 1. 20. 14:55

강의

# 스택

나중에 넣은 데이터를 먼저 반환하도록 설계된 메모리 구조

데이터의 입력을 push, 출력을 pop이라고 함

파이썬에서는 리스트를 사용하여 스택구조 구현

a = [1, 2, 3, 4, 5]
a.append(10) # a == [1, 2, 3, 4, 5, 10]
b = a.pop() # b==10, a == [1, 2, 3, 4, 5]

# 큐

먼저 넣은 데이터를 먼저 반환하도록 설계된 메모리 구조

파이썬에서는 리스트를 사용하여 큐 구조 구현

a.append(10)
a.pop(0)

 

# 튜플

값의 변경이 불가능한 리스트

리스트의 연산, 인덱싱, 슬라이싱은 모두 사용 가능하다.

 

# 집합

값을 순서없이 저장, 원소의 중복은 제거된다.

a.add(b) # b를 원소로 추가한다.
a.remove(b) # b를 원소에서 삭제한다. b가 원소로 없을때에는 에러가 발생한다.
a.discard(b) # b가 원소로 있으면 없어지고 없더라도 에러가 발생하지 않는다.
a.update([1,2,3,4,5]) # 새로운 원소 뭉탱이를 추가한다.
s1.union(s2) # 합집합
s1 | s2 # 합집합
s1.intersection(s2) # 교집합
s1 & s2 # 합집합
s1.difference(s2) # 차집합
s1 - s2 # 차집합

 

# 사전

key값과 value값을 동시에 저장

다른 언어에서는 해시테이블이라는 용어를 사용

a.items()

a.keys()

a.items()

a.values()

 

# collection 모듈

from collections import deque

from collections import Counter

from collections import OrderedDict

from collections import defaultdict

from collection import namedtuple

 

# deque

from collections import deque

a = deque()

a.appendleft(b)

a.popleft(b)

a.rotate(1)

a.extend([1,2,3])

a.extendleft([1,2,3])

# OrderedDict

사전에 입력되는 순서를 보장하지만, 현재는 기본 dict도 지원된다.

 

# defaultdict

사전의 초기값을 넣어주며, 없는 키를 요청할때 기본값으로 value를 만들어준다.

초기값은 lambda: 0 과 같이 defaultdict를 만들때 람다로 적어준다.

 

# Counter

시퀀스 데이터 타입에서 element의 갯수를 세준다.

거꾸로 Counter에서 선언하고 시퀀스 데이터로 뺄 수도 있다.

c = Counter(cats=1, dogs=1)

print(list(c.elements()))

['cats', 'dogs', 'dogs']

set에서 사용하는 연산들이 그대로 사용 가능하다.

a.subtract(b)

 

# namedtuple

튜플 형태로 데이터를 구조체를 저장하는 방법

칼럼정보를 넣어서 보여줄수 있다는 장점이 있다.

Point = namedtuple('Point', ['x', 'y'])

p = Point(11, y=22)

print(p.x, p.y)

# pythonic code

파이썬에서 잘쓰이는 코드 테크닉들이 있다.

많은 개발자들이 이런 스타일로 코딩하므로, 이해가 필요하다.

코드가 짧아지고 더 효율적인 경우가 많다.

split & join

list comprehension

enumerate & zip

lambda & map & reduce

generator

asterisk

 

# split & join

빈칸을 기준으로 리스트를 만들어서 반환한다.

split()안에 구분자를 넣어주면 구분자를 기준으로 리스트를 만들어 준다.

" ".join(리스트)를 사용하면 리스트를 띄어쓰기로 구분한 문자열로 합쳐서 반환한다.

 

# list comprehension

기존 list를 사용하여 다른 list를 만드는 방법

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

result = [i for i in range(10)]

case1 = ["A", "B", "C"]

case2 = ["D", "E", "A"]

result = [i+j for i in word1 for j in word2] # ["AD", "AE", "AA", "BD", "BE", "BA", "CD", "CE", "CA"]

 

# filter

if문을 사용하여 필터링이 가능한데, if문은 for문 뒤에 위치한다.

result = [i for i in range(10) if i % 2 == 0]

else문을 사용할 수 있는데 그럴 경우에는 if else문 전체가 for문 앞으로 이동하게 된다.

result = [i+j if not(i==j) else i for i in case1 for j in case2]
# ["AD", "AE", "BD", "BE", "BA", "CD", "CE", "CA"]

 

# pprint

import pprint

pprint.pprint(리스트) # 사용하면 배열이 아래로 나열되면서 이쁘게 출력된다.

 

# 행렬만들기

result = [[i+j for i in case1 if i!="C"] for j in case2]

 

# enumerate

인덱스도 함께 반환된다.

{v.lower() : i for i, v in enumerate(set_text)}

 

# zip

두개의 리스트 값을 병렬적으로 추출할때 사용한다.

튜플이 반환된다.

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] for a, b in zip(alist, blist)]

# [['a1', 'b1'], ['a2', 'b2'], ['a3', 'b3']]

[c for c in zip(alist, blist)]

# [('a1', 'b1'), ('a2', 'b2'), ('a3', 'b3')]

 

# lambda

함수 이름 없이 함수처럼 쓸수 있는 익명 함수다

f = (lambda x, y: x+y)

f(10, 50) # 60

(lambda x, y: x+y)(10, 50) # 60

 

# lambda의 문제점

문법이 어렵다

테스트가 어렵다

문서화 할 수 있는 docstring 지원이 되지 않는다

코드 해석이 어렵다

 

# map

iterable에 각각 어떤 함수를 적용해 반환한다.

ex = [1, 2, 3, ,4 ,5]

f = lambda x: x**2

list(map(f, ex)) # [1, 4, 9, 16, 25]

f = lambda x, y: x + y

list(map(f, ex, ex)) # 람다의 파라미터가 두개일때는 파라미터를 두번 넣어 zip처럼 사용할 수 있다.

list(map(lambda x: x**2 if x%2==0 else x, ex)) # 조건문도 사용할 수 있다.

다만, 리스트 컴프리헨션을 사용하는게 더 간편한 경우가 많다.

 

# reduce

누산개념이 적용된다.

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

 

# lambda, map, reduce

간단한 코드로 다양한 기능을 제공한다.

하지만 직관성이 떨어지기 때문에 lambda와 reduce는 파이썬3에서 사용을 지양하는 분위기이다.

다만, 레거시에서 여전히 사용중인 경우가 많다.

 

# iterator

내부적 구현으로 __iter__와 __next__가 사용된다.

리스트에서의 첫 주소값을 가져와 구성한다.

iterator= iter(리스트)

다음 값을 가져올때는 next함수를 사용한다.

next(iterator)

 

# generator

iterable object를 특수한 형태롤 사용해주는 함수이다.

요수가 사용되는 시점에 값을 메모리에 반환한다.

return 대신 yield를 사용하여 반환이 여러번 가능한 함수로, 메모리 절약이 가능하다.

데이터를 한번에 가지고 있는게 아니라, 데이터를 뽑아주는 자판기를 가지고 있는 개념이다.

 

# generator comprehension

generator 형태의 리스트를 만들 수 있다.

[] 대신 ()를 사용하여 표현한다.

gen_ex = (n*n for n in range(500))

 

 

# function passing arguments

1. keyword arguments

2. default arguments

3. variable-length arguments

 

# keyword arguments

print_somthing(your_name="TEAMLAB", my_name="sungchul")

 

 

# default arguments

함수를 선언할때 기본 값을 설정할 수 있다.

def print_somthing(my_name, your_name="TEAMLAB")

print_somthing("내이름", "TEAMLAB")

print_somthing("내이름")

# variable-length arguments(가변인자)

개수가 정해지지 않은 변수를 함수의 parameter로 사용하는 방법

keyword arguments와도 함께 사용 할 수 있다

asterisk(*)기호를 사용해서 함수의 parameter를 표시한다

입력된 값은 tuple type으로 사용할 수 있다

가변인자는 딱 한개만 마지막 parameter 위치에서 사용할 수 있다

가변인자는 일반적으로 *args를 변수명으로 사용한다

기존 parameter 이후에 나오는 값을 tuple롤 저장한다

def asterisk_test(a, b, *args):
    return a+b+sum(args)

print(asterisk_text(1,2,3,4,5))

 

# keyword variable-length(키워드 가변인자)

파라미터 이름을 따로 지정하지 않고 입력하는 방법이다.

asterisk 두개를 사용하여 함수의 parameter를 표시한다.

입력된 값은 dict type으로 사용할 수 있다.

def kwargs_test_1(**kwargs):
    print(kwargs)

kwargs_test_1(first=3, second=4, third=5)

 

# 복잡한 형태의 키워드 가변인자

가변인자로 파라미터를 정의하는 순서는 정해져있다.

def kwargs_test_3(one, two, *args, **kwargs):
    print(one+two+sum(args))
    print(kwargs)

kwargs_test_3(3,  4,  5,6,7,8,9,  first=3,second=4,third=5)

 

# asterisk

단순곱셈, 제곱연산, 가변인자활용 등으로도 사용되지만...

unpacking container로 사용할 수 있다.

tuple, dict등 자료형에 들어가 있는 값을 unpacking한다

함수의 입력값, zip등에 유용하게 사용이 가능하다.

def asterisk_test(a, *args):
    ....

asterisk_test(1, *(2,3,4,5,6))
ex = ([1,2], [3,4], [5,6], [5,6], [5,6])
for value in zip(*ex):
    print(value)

 

dict 타입에 사용할때는 **args와 같이 두번 사용한다.

def asterisk_test(a, **args):
    ....