새싹 인공지능 응용sw 개발자 양성 교육 프로그램 심선조 강사님 수업 정리 글입니다.
목차
원문
https://numpy.org/numpy-tutorials/content/tutorial-svd.html
컴퓨터에 matplotlib 및 SciPy 도 설치되어 있어야 한다.
from scipy import misc
img = misc.face()
img.ndim
>>3
img.shape
#3개 열, 1024개 있다, 이런 데이터가 768개 있다
>>(768, 1024, 3)
#이미지는 기본 가로세로가 있다. 가로 1024, 세로 768, 3개는
img.size #요소수
>>2359296
img.dtype
>>dtype('uint8')
type(img) #type은 numpy의 기본적인 형태 "ndarray" = 배열
>>numpy.ndarray
img #121, 112, 131 = rgb
#숫자값의 범위가 궁금하면 img[0,0,0] -> 121
>>array([[[121, 112, 131],
[138, 129, 148],
[153, 144, 165],
...,
[119, 126, 74],
[131, 136, 82],
[139, 144, 90]],
[[ 89, 82, 100],
[110, 103, 121],
[130, 122, 143],
...,
[118, 125, 71],
[134, 141, 87],
[146, 153, 99]],
[[ 73, 66, 84],
[ 94, 87, 105],
[115, 108, 126],
...,
[117, 126, 71],
[133, 142, 87],
[144, 153, 98]],
...,
[[ 87, 106, 76],
[ 94, 110, 81],
[107, 124, 92],
...,
[120, 158, 97],
[119, 157, 96],
[119, 158, 95]],
[[ 85, 101, 72],
[ 95, 111, 82],
[112, 127, 96],
...,
[121, 157, 96],
[120, 156, 94],
[120, 156, 94]],
[[ 85, 101, 74],
[ 97, 113, 84],
[111, 126, 97],
...,
[120, 156, 95],
[119, 155, 93],
[118, 154, 92]]], dtype=uint8)
img[0,0,0]
>>121
img[0,0, :]
>>array([121, 112, 131], dtype=uint8)
img[0,:,:]
>>array([[121, 112, 131],
[138, 129, 148],
[153, 144, 165],
...,
[119, 126, 74],
[131, 136, 82],
[139, 144, 90]], dtype=uint8)
img.max() #요소값중 가장 큰 것 , 경우의 수는 256 = 8byte로 표현, #nomalization, 데이터가 큰 값을 조정하는 것
>>255
img.min() #요소값중 가장 작은 것
>>0
선형 대수학에서 벡터의 차원은 배열의 항목 수를 나타냅니다. NumPy에서는 대신 축 수를 정의합니다. 예를 들어 1D 배열은 와 같은 벡터 이고 2D 배열은 행렬입니다.[1, 2, 3]
import matplotlib.pyplot as plt
#matplotlib = 파이썬에서 차트를 그려주는 기본적인 라이브러리
%matplotlib inline #요즘에는 안 적어도 사진 나옴
plt.imshow(img)
plt.show
img[:,:,0] # 0= r값 (rgb)
>>array([[121, 138, 153, ..., 119, 131, 139],
[ 89, 110, 130, ..., 118, 134, 146],
[ 73, 94, 115, ..., 117, 133, 144],
...,
[ 87, 94, 107, ..., 120, 119, 119],
[ 85, 95, 112, ..., 121, 120, 120],
[ 85, 97, 111, ..., 120, 119, 118]], dtype=uint8)
img[:,:,1] # 0= g값 (rgb)
>>array([[112, 129, 144, ..., 126, 136, 144],
[ 82, 103, 122, ..., 125, 141, 153],
[ 66, 87, 108, ..., 126, 142, 153],
...,
[106, 110, 124, ..., 158, 157, 158],
[101, 111, 127, ..., 157, 156, 156],
[101, 113, 126, ..., 156, 155, 154]], dtype=uint8)
img[:,:,1].shape #이미지의 사이즈를 보여준다.
>>(768, 1024)
#조정할 때는 가장 큰 숫자 값으로 나누면 값이 조정이 된다. -> 값이 0~1사이 값으로 변함 = 그래도 사진은 차이가 없다.
img_array = img / 255
img_array.max(),img_array.min()
>>(1.0, 0.0)
plt.imshow(img_array) #값이 변했다고 달라지는 것은 없음
plt.show()
img_array.dtype #int가 255나누기 작업을 통해서 float로 변했음
>>dtype('float64')
img.shape
>>(768, 1024, 3) # 3개가 나왔으니 3차원이다, channel은 열
슬라이스 구문을 사용하여 각 색상 채널을 별도의 행렬에 할당할 수 있습니다.
red_array = img_array[:, :, 0]
green_array = img_array[:, :, 1]
blue_array = img_array[:, :, 2]
SVD(Singular Value Decomposition)
행렬을 특정한 구조로 분해하는 방식
출처)https://ko.wikipedia.org/wiki/%ED%8A%B9%EC%9E%87%EA%B0%92_%EB%B6%84%ED%95%B4
img 1024, 768
u = 1024 768
시그마 = 1024 768 , 대각선으로만 값이 있고 나머지 값은 다 0 이다.
v = 1024 768 , 전치행렬해서 곱하면 된다.
@연산자 = 행렬곱
[1, 2] * 2 =[2, 2] # 스칼라값 곱할 때
전제조건
앞 쪽의 열값과 뒤 쪽의 행 값이 같아야 한다.
결과
앞 쪽의 행 값과 뒤 쪽의 열값의 곱으로 나온다.
ex) 10 * 5 , 바깥쪽의 값들 곱으로 나온다.
출처) https://dudri63.github.io/2019/01/28/algo20/
img_gray.shape #그레이스케일 정보
>>(768, 1024)
u @ s = 가능 768, 768, 같아서
u @ vt = 불가능 768, 1024 달라서
U,s,Vt = linalg.svd(img_gray)
U.shape,s.shape,Vt.shape
>>((768, 768), (768,), (1024, 1024))
#특이값 분해는 하나의 행렬이 3개의 열로 분해가 된다.
U @ s
>>array([-14.82934258, -15.64213083, -14.11270338, -11.83441097,
-11.22274112, -12.0353505 , -13.47822804, -14.71083649,
-12.81620569, -14.75900199, -16.39875751, -15.92262872,
-14.2169179 , -15.3288541 , -14.70930414, -12.08341602,
-13.22480892, -17.99291819, -18.52242787, -16.64750177,
-15.22914737, -13.38720335, -10.1227432 , -7.90847967,
-9.96630176, -12.48284105, -8.99099249, -6.41657917, 생략
# 사이즈가 안 맞아서 대각행렬을 이용해야 한다.
#((768, 768), (768,), (1024, 1024)) 768, 1024, 둘 의 값이 안 맞아서
s @ Vt
>>오류
import numpy as np
Sigma = np.zeros((U.shape[1],Vt.shape[0]))
Sigma.shape
>>(768, 1024)
np.fill_diagonal(Sigma, s) #fill= 대각선으로 값을 채움, (Sigma, s) = Sigma에 s값을 채워라
Sigma
>>array([[410.42098224, 0. , 0. , ..., 0. ,
0. , 0. ],
[ 0. , 85.56090199, 0. , ..., 0. ,
0. , 0. ],
[ 0. , 0. , 63.61066707, ..., 0. ,
0. , 0. ],
...,
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ]])
U@Sigma@Vt #원래대로 복원
>>array([[0.45209882, 0.51876549, 0.57815529, ..., 0.47355843, 0.51387529,
0.54524784],
[0.33250118, 0.41485412, 0.49104706, ..., 0.46907059, 0.53181569,
0.57887451],
[0.26975608, 0.35210902, 0.43446196, ..., 0.47104157, 0.53378667,
0.57692392],
...,
[0.39135137, 0.40982196, 0.46304078, ..., 0.5706549 , 0.56673333,
0.5692549 ],
[0.37452784, 0.41374353, 0.47675608, ..., 0.56840078, 0.56419608,
0.56419608],
[0.37509412, 0.42158667, 0.47340078, ..., 0.56447922, 0.56027451,
0.55635294]])
#특이값 분해는 값이 3개로 분해가 된다. 2. 대각선만 값이 있는 부분만 return 3. 1024 * transpose값만 return이 된다.
분해 된 것은 합칠 수 있다. 중간에 있는 값이 대각선마 있는 값을 복원할려면 대각행렬로 바꿔야 한다.
Sigma = np.zeros((U.shape[1],Vt.shape[0])) Sigma.shape 대각선으로 값으로 채우는 작업이다. np.fill_diagonal(Sigma, s) #fill= 대각선으로 값을 채움, (Sigma, s) = Sigma에 s값을 채워라
linalg.norm(img_gray - U @ Sigma @ Vt)
>> 1.4049006864018454e-12
이 값이 작으면 차이가 별로 없는 것
#원래값과 이것이 차이가 있느냐 없느냐를 체크하는 함수 2개
linalg.norm(img_gray - U@Sigma@Vt) # 결과값이 0에 가깝기 때문에 원상복구가 됬다.
>>1.4108253216554015e-12
#원래값과 이것이 차이가 있느냐 없느냐를 체크하는 함수 2개, true = 원상복구됨
np.allclose(img_gray, U @ Sigma @ Vt)
>>Ture
#데이터를 압축해서 쓸 수 있다는 것은
k = 500
approx = U @ Sigma[:,:k] @ Vt[:k,:]#u =768 @뒤가 1024, 열은 768개 사용하고 행은 10개만 사용하겠다 , ;=전부다
plt.imshow(approx,cmap='gray')
plt.show
NumPy의 선형 대수 모듈인 numpy.linalg 를 사용하여 수행
이 모듈의 대부분의 선형 대수 함수는 scipy.linalg 에서도 찾을 수 있으며 사용자는 실제 응용 프로그램에 scipy 모듈을 사용하는 것이 좋습니다.
from numpy import linalg # 특이값 분해 svd, linalg= 선형대수학
img_gray = img_array @ [0.2126, 0.7152, 0.0722] #컬럼값으로 그레이스케일로 바꾸는 공식, 컬럼 -> 그레이스케일
이 함수는 매개변수의 값에 따라 8개의 서로 다른 행렬 노름 중 하나 또는 무한한 수의 벡터 노름(아래 설명) 중 하나를 반환할 수 있다.
분해된 것은 복원할 떄 모든 데이터가 필요한 것이 아니라 일부 데이터만 있어도 가능하다.
특이값 분해를 우리가 직접하지는 않지만 어떻게 작동하는 지만 알기.
from PIL import Image
img_path = 'img01.jpg'
img = Image.open(img_path).convert('L') #).convert('L') = 그레스이스케일
plt.imshow(img)
plt.show()
type(img)
>>numpy.ndarray
img
>>array([[[121, 112, 131],
[138, 129, 148],
[153, 144, 165],
...,
[119, 126, 74],
[131, 136, 82],
[139, 144, 90]], 생략
np.array(img)
>>array([[[121, 112, 131],
[138, 129, 148],
[153, 144, 165],
...,
[119, 126, 74],
[131, 136, 82],
[139, 144, 90]], 생략
np.array(img)
>>array([[[121, 112, 131],
[138, 129, 148],
[153, 144, 165],
...,
[119, 126, 74],
[131, 136, 82],
[139, 144, 90]], 생략
import cv2
img = cv2.imread(img_path)
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
img
array([[[121, 152, 181],
[120, 151, 180],
[120, 151, 180],
...,
[113, 146, 177],
[113, 146, 177],
[113, 146, 177]], 생략
csv - ,으로 구분된 파일
tsv - tab으로 구분된 파일
pandas의 기본 베이스는 numpy이다
import pandas as pd
df = pd.read_csv('data/gapminder.tsv',sep='\t') #sep='\t'tab으로 구분되어 있다
type(df)
>>pandas.core.frame.DataFrame
시리즈 : 열, 같은 종류의 data
데이터프레임 : 시리즈들이 각 요소가 되는 딕셔너리
print(df.head(5))
>>
country continent year lifeExp pop gdpPercap
0 Afghanistan Asia 1952 28.801 8425333 779.445314
1 Afghanistan Asia 1957 30.332 9240934 820.853030
2 Afghanistan Asia 1962 31.997 10267083 853.100710
3 Afghanistan Asia 1967 34.020 11537966 836.197138
4 Afghanistan Asia 1972 36.088 13079460 739.981106
print(df.head(2)) #위에서 5개
>>
country continent year lifeExp pop gdpPercap
0 Afghanistan Asia 1952 28.801 8425333 779.445314
1 Afghanistan Asia 1957 30.332 9240934 820.853030
df.shape
>>(1704, 6)
df.size
>>10224
df.ndim
>>2
데이터 프레임의 열이름을 보여준다.
df.columns
>>Index(['country', 'continent', 'year', 'lifeExp', 'pop', 'gdpPercap'], dtype='object')
df.index #일련번호가 잇다.
>>RangeIndex(start=0, stop=1704, step=1)
df.values
>>array([['Afghanistan', 'Asia', 1952, 28.801, 8425333, 779.4453145],
['Afghanistan', 'Asia', 1957, 30.332, 9240934, 820.8530296],
['Afghanistan', 'Asia', 1962, 31.997, 10267083, 853.10071],
...,
['Zimbabwe', 'Africa', 1997, 46.809, 11404948, 792.4499603],
['Zimbabwe', 'Africa', 2002, 39.989, 11926563, 672.0386227],
['Zimbabwe', 'Africa', 2007, 43.487, 12311143, 469.7092981]],
dtype=object)
df.dtypes #numpy는 한 종류의 타입만 올 수 있다. df는 열마다 다른 타입도 가능하다. #컬럼이름, 타입명, object = str
>>country object
continent object
year int64
lifeExp float64
pop int64
gdpPercap float64
dtype: object
df.info() # RangeIndex: 1704 entries, 0 to 1703 = null값이 없다
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1704 entries, 0 to 1703
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 country 1704 non-null object
1 continent 1704 non-null object
2 year 1704 non-null int64
3 lifeExp 1704 non-null float64
4 pop 1704 non-null int64
5 gdpPercap 1704 non-null float64
dtypes: float64(2), int64(2), object(2)
memory usage: 80.0+ KB
df['country']
>>
0 Afghanistan
1 Afghanistan
2 Afghanistan
3 Afghanistan
4 Afghanistan
...
1699 Zimbabwe
1700 Zimbabwe
1701 Zimbabwe
1702 Zimbabwe
1703 Zimbabwe
Name: country, Length: 1704, dtype: object
type(df['country']) #Series = 데이터 타입
>>pandas.core.series.Series
df['country'].head()
>>
0 Afghanistan
1 Afghanistan
2 Afghanistan
3 Afghanistan
4 Afghanistan
Name: country, dtype: object
df['country'].tail()
>>
1699 Zimbabwe
1700 Zimbabwe
1701 Zimbabwe
1702 Zimbabwe
1703 Zimbabwe
Name: country, dtype: object
df['country'].sample(2)
>>
22 Albania
1407 South Africa
Name: country, dtype: object
loc: 인덱스를 전달하면 행 단위로 데이터 추출, 부여된 명칭으로 불러야 한다.
iloc: 특정 열 값 추출 (i = index)
df.loc[0] #첫번째 인덱스 값을 가져와라 # 한 행만 가져와서 series형태로 출력, pandas처럼 표형식으로 출력 안 됨
>>
country Afghanistan
continent Asia
year 1952
lifeExp 28.801
pop 8425333
gdpPercap 779.445314
Name: 0, dtype: object
df.iloc[-1] #loc는 부여된 이름이라서 -1은 index인 iloc만 가능하다.
>>
country Zimbabwe
continent Africa
year 2007
lifeExp 43.487
pop 12311143
gdpPercap 469.709298
Name: 1703, dtype: objectS
df.iloc[0] #첫 번째 행의 값을 가져와라
>>
country Afghanistan
continent Asia
year 1952
lifeExp 28.801
pop 8425333
gdpPercap 779.445314
Name: 0, dtype: object
df.iloc[0,0] #첫 번째 행의 첫 번째 열의 값을 가져와라
>>'Afghanistan'
df.iloc[-1]
>>country Zimbabwe
continent Africa
year 2007
lifeExp 43.487
pop 12311143
gdpPercap 469.709298
Name: 1703, dtype: object
import pandas as pd
s = pd.Series(['banana',42])
s
>>
0 banana
1 42
dtype: object
s = pd.Series(['Wes','pandas'],index=['person','who']) # index=['person','who'] = index이름 설정
s
>>
person Wes
who pandas
dtype: object
scientists = pd.DataFrame({
'Name':['rosa','will'],
'occupation':['chemist', 'Statistician'],
'Born':['1920-07-25', '1876-06-13'],
'Died':['1958-04-16', '1937-10-16'],
'Age':[37, 61]}
)
print(scientists)
>>
Name occupation Born Died Age
0 rosa chemist 1920-07-25 1958-04-16 37
1 will Statistician 1876-06-13 1937-10-16 61
df = pd.read_csv('data/scientists.csv')
df.index
>>RangeIndex(start=0, stop=8, step=1)
df.columns
>>Index(['Name', 'Born', 'Died', 'Age', 'Occupation'], dtype='object')
df.values
>>array([['Rosaline Franklin', '1920-07-25', '1958-04-16', 37, 'Chemist'],
['William Gosset', '1876-06-13', '1937-10-16', 61, 'Statistician'],
['Florence Nightingale', '1820-05-12', '1910-08-13', 90, 'Nurse'],
['Marie Curie', '1867-11-07', '1934-07-04', 66, 'Chemist'],
['Rachel Carson', '1907-05-27', '1964-04-14', 56, 'Biologist'],
['John Snow', '1813-03-15', '1858-06-16', 45, 'Physician'],
['Alan Turing', '1912-06-23', '1954-06-07', 41,
'Computer Scientist'],
['Johann Gauss', '1777-04-30', '1855-02-23', 77, 'Mathematician']],
dtype=object)
df.keys() #columns와 결과값은 같지만 columns는 속성이라 ()안 쓰지만 keys는 매소드라 ()사용
>>Index(['Name', 'Born', 'Died', 'Age', 'Occupation'], dtype='object')
#시리즈의 기초 통계 메서드 사용하기
#mean = 평균, max,min,std= 표준편차
df['Age']
>>0 37
1 61
2 90
3 66
4 56
5 45
6 41
7 77
Name: Age, dtype: int64
df['Age'].mean()
>>59.125
df.describe() #숫자형은 Age뿐이라서 Age만 나옴
>>Age
count 8.000000
mean 59.125000
std 18.325918
min 37.000000
25% 44.000000
50% 58.500000
75% 68.750000
max 90.000000