👩‍💻LEARN : ML&Data/Book Study

[알고리즘 구현으로 배우는 선형대수] #1. 선형대수를 위한 기초 파이썬

쟈니유 2023. 3. 17. 15:19
728x90

벗어날 수 없는 행렬의 굴레여...

 


#1. 선형대수를 위한 기초 파이썬 

 

선형대수에 필요한 내용 위주로만 정리해보았다. 

 

1.1 복사

 
✔️ 객체의 복사 : 행렬을 다룰 때 리스트 자료형을 복사하는 경우에 적용
  • 종류 : 얕은 복사, 깊은 복사
  • 방법 차이 : 객체의 종류에 따라 복사 방법에 차이가 생김
 
✔️ 객체의 종류
  • mutable(id 변경 가능) : 리스트
  • immutable(id 변경 불가능) : 숫자, 문자
 
 
 

1.2 얕은 복사

  • 서로 다른 객체의 변경이 서로에게 영향을 끼치지 않도록 하는 것
 

얕은 복사 방법 1. 리스트 슬라이싱 사용하기

a = [1,2,3,4,5]
b = a[:]  #얕은 복사를 이용하여 리스트a를 b에 할당하는 코드

print(id(a),id(b), id(a[0]), id(b[0]))
140603143313408 140602089407808 140603136600368 140603136600368
 
→ 리스트 a,b의 주소값은 다르지만 같은 인덱스의 주소는 같은 것을 확인할 수 있다
b[0]=9

print(a,b)
print(id(a[0]), id(b[0]))
[1, 2, 3, 4, 5] [9, 2, 3, 4, 5]
140603136600368 140603136600624
 
→ b의 원소를 변경했을 때, a에는 반영되지 않으며 원래 동일했던 메모리주소도 변경된 것을 확인할 수 있다.
 

얕은 복사 방법 2. copy 라이브러리 사용하기

import copy

a = [1,2,3,4,5]
b = copy.copy(a)

b[0]=8

print(id(a), id(b))
print(id(a[0]), id(b[0]))
140603143310464 140603143334144
140603136600368 140603136600592
 
→ b의 원소 변경 전에는 원소 주소값이 같으나 (여기엔 작성하지 않음), 변경 이후엔 달라지는 것을 확인할 수 있음
 

얕은 복사 방법 3. mutable한 객체 내부에 mutable한 객체가 속한 경우

 
→ b의 리스트의 원소 b[0][0]만 변경했어도 a[0][0]이 영향 받음 = 얕은 복사 불가능
→ 이와 같은 경우 깊은 복사를 사용해서 mutable 객체 속에 mutable 객체를 변경해야 함
 
 

1.3 깊은 복사

  • mutable한 객체 내부에 mutable한 객체가 속한 경우에도 복사하기
 
import copy

a = [1,2,3,4,5]
b = copy.deepcopy(a)

print(a,b)
# 출력값 : [[1, 2], [3, 4]] [[1, 2], [3, 4]]

print(id(a), id(b), id(a[0]), id(b[0]), id(a[0][0]), id(b[0][0]))
# 출력값 : 140603143232576 140603143309312 140603143309248 140603143243264 140603136600368 140603136600368

b[0][0] = 7
print(a,b)
print(id(a[0][0]), id(b[0][0]))
# 출력값 : [[1, 2], [3, 4]] [[7, 2], [3, 4]], 140603136600368 140603136600560
→ a와 b 의 주소, 각각의 첫번째 리스트의 주소는 다르지만 첫번째 리스트의 원소 주소는 같은 것을 확인
→ b의 첫번째 리스트의 첫번째 원소 값을 변경했을 때, 해당 주소가 변경되는 것을 확인
 
깊은 복사 구현하기
def zeromat(n,p):                 #영행렬 구현 
    Z = []
    for i in range (0,n):         #다음 내용을 행의 수 n 만큼 반복하라 
        row= []
        for j in range (0,p):         # 열의 수 p 만큼 0 을 row에 추가한다 
            row.append(0)
        Z.append(row)                 # row를 Z에 추가한다 
    return Z 

def deepcopy(A):
    if type(A[0]) == list :                   #A가 행렬이라면 
        n=len(A)                                ##행 
        p=len(A[0])                             ##열 
        res = zeromat(n,p)    #res : 복사 결과를 넣을 영행렬을 만들어라 
        
        for i in range(0,n):    #행의 수 n 만큼 아래 내용을 반복 
            for j in range (0,p) :     #영행렬 res에 A의 원소를 추가하는 일을 열의 수 p만큼 반복 
                res[i][j] = A[i][j]
        return res 
    else :                                   #A가 벡터라면 
        n=len(A)
        res = []
        for i in range (0,n):            #A의 원소 수 만큼 A의 원소를 빈 리스트 res에 넣는 것을 반복 
            res.append(A[i])
        return res