이미지를 받아오고 panel에 들어온 값에 따라 해상도(?)를 설정하여 픽셀의 형태로 만드는 코드

 

import cv2

file_name = 'rosicky.jpg'
image = cv2.imread(file_name)

panel = np.zeros([100,400], np.uint8)
cv2.namedWindow('panel')

def nothing(x):
    pass

cv2.createTrackbar('FX', 'panel', 1,100, nothing)
cv2.createTrackbar('FY', 'panel', 1,100, nothing)

return_name = file_name.replace('.','_pixel.')

while True:
    
    # 트랙바의 위치에 따라 변수에 값할당
    fx = cv2.getTrackbarPos('FX', 'panel') / 100
    fy = cv2.getTrackbarPos('FY', 'panel') / 100

    pixel = cv2.resize(image, dsize=None, fx=fx, fy=fy, interpolation=cv2.INTER_NEAREST)
    pixel = cv2.resize(pixel, dsize=(int(image.shape[1]*1),int(image.shape[0]*1)), interpolation=cv2.INTER_NEAREST)
    
    cv2.imshow('image', image)
    cv2.imshow('pixel', pixel)
    cv2.imshow('panel', panel)
    
    if cv2.waitKey(1) == ord('s'):
        cv2.imwrite(return_name, pixel)
    if cv2.waitKey(1) == ord('q'):
        break

cv2.waitKey(0)
cv2.destroyAllWindows()

 

pixel = cv2.resize(image, dsize=None, fx=fx, fy=fy, interpolation=cv2.INTER_NEAREST)

pixel = cv2.resize(pixel, dsize=(int(image.shape[1]*1),int(image.shape[0]*1)), interpolation=cv2.INTER_NEAREST)

 

이미지의 사이즈를 조정하는 방법 중 제일 퀄리티가 떨어지게되는 INTER_NEAREST 옵션을 사용하여 줄이고 다시 원래크기로 복원하여 해상도를 낮게 만들어 픽셀화한다.

panel에 크기를 줄이는 가중치를 받아와 실시간으로 결과가 어떻게 변하는지를 확인할 수 있도록함

 

s를 입력시 동명의 이름에 _pixel이 붙은 상태로 저장이되고 

q를 입력시 종료된다.

'CV > open cv' 카테고리의 다른 글

[cv] 얼굴인식하여 얼굴부분만 모자이크하기  (2) 2022.04.14

뉴스나 인터넷 방송, 영화촬영에 사용하는 크로마키 배경을 제거하는 방법을 파이썬으로 구현

 

 

1. 크로마키란

 

화면 합성 등의 특수 효과를 이용하기 위해 이용하는 배경. 흔히 초록색과 파란색을 사용하여 그린 스크린, 블루 스크린이라고도 한다. 촬영 과정에서 배우가 단색 배경 앞에서 연기를 하고 후편집 과정에서 같은 색으로 찍힌 부분을 다른 배경으로 바꾸면 바꾼 배경에서 연기한 것과 같은 효과를 낼 수 있다.

원래는 'chroma key'로 두 단어이지만 한국에서는 한 단어인 것처럼 '크로마키'라고 쓴다

 

[출처] 나무위키

 

[출처] http://news.samsungdisplay.com/15102

2. 크로마키의 원리 

초록색배경을 투명화하는 것이다.

원래 크로마키 기술에서는 어떻게 적용되는지는 모르겠으나 파이썬에서는 초록색이 아닌부분을 추출하고 그 부분을 배경으로원하는 부분위에 올려다 놓는다.

 

3. 코드 

 

좌측과 중앙이미지를 결합하여 우측이미지를 만든다

 

import cv2
import numpy as np

cap = cv2.imread('chim55cap.png')

# 배경사이즈를 타겟이미지와 맞춤
window = cv2.imread('windowbg.jpg')
window = cv2.resize(window, (cap.shape[1],cap.shape[0])) # width, height 고정 크기

# 트랙바 생성
panel = np.zeros([100,400], np.uint8)
cv2.namedWindow('panel')

def nothing(x):
    pass

# 트랙바의 범위 설정
cv2.createTrackbar('L-H', 'panel', 0,179, nothing)
cv2.createTrackbar('U-H', 'panel', 179,179, nothing)

cv2.createTrackbar('L-S', 'panel', 0,255, nothing)
cv2.createTrackbar('U-S', 'panel', 255,255, nothing)

cv2.createTrackbar('L-V', 'panel', 0,255, nothing)
cv2.createTrackbar('U-V', 'panel', 255,255, nothing)

# 초록면 없애기 위해 hsv로 변환
hsv = cv2.cvtColor(cap, cv2.COLOR_BGR2HSV)
while True:
    
    # 트랙바의 위치에 따라 변수에 값할당
    l_h = cv2.getTrackbarPos('L-H', 'panel')
    u_h = cv2.getTrackbarPos('U-H', 'panel')
    l_s = cv2.getTrackbarPos('L-S', 'panel')
    u_s = cv2.getTrackbarPos('U-S', 'panel')
    l_v = cv2.getTrackbarPos('L-V', 'panel')
    u_v = cv2.getTrackbarPos('U-V', 'panel')
    
    lower_green = np.array([l_h,l_s,l_v])
    upper_green = np.array([u_h,u_s,u_v])
    
    # 범위사이에 있는 놈들을 마스크로 만들어라
    mask = cv2.inRange(hsv, lower_green, upper_green) 
    mask_inv = cv2.bitwise_not(mask) # 마스크를 거꾸로만들어라
    
    bg = cv2.bitwise_and(cap, cap, mask=mask) # lg와 ug 사이 놈들을 마스크 사이놈들만 살린다
    
    # 침착맨의 실루엣을 추출(마스킹)
    fg = cv2.bitwise_and(cap, cap, mask=mask_inv) # 위에거의 반대
    
    # 윈도우 배경에서 침착맨의 실루엣을 제거
    window_bg = cv2.bitwise_and(window, window, mask=mask) 
    
    # 두화면을 더함
    result = cv2.addWeighted(src1 = fg, src2=window_bg, alpha=1, beta=1, gamma=0)

#     cv2.imshow('bg', bg)
#     cv2.imshow('fg', fg)
#     cv2.imshow('window', window_bg)
    cv2.imshow('result', result)
    cv2.imshow('panel', panel)
    
    if cv2.waitKey(1) == ord('q'):
        break

    cv2.imwrite('result.png', result) # png 형태로 저장
    
cv2.destroyAllWindows()

실행하면 트랙바가 생기게 되는데 

트랙바의 위치 즉 마스킹을 할 범위에 따라서 타겟 이미지가 마스킹 될지 안될지 변한다 트랙바를 적절히 변경을하고 키보드의 q를 누르면 저장이되고 해당 셀이 종료되는 코드이다..

 

간단하게 원리를 알아보면 

 

\

 

이미지의 색을 hsv로 변환시켜서  설정한 hsv값의 범위안에 속하는 녀석들만 남기는 것이다.

배경은 그것의 반대로 응용하고 두개를 합치면된다.

 

 

4. 영상에서 응용

 

cap = cv2.VideoCapture('chim55.mp4')

window = cv2.imread('windowbg.jpg')
# 코덱 정의
fourcc = cv2.VideoWriter_fourcc(*'DIVX')

# 프레임 크기, FPS
width = round(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = round(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS) 

# 저장 파일명, 코덱, FPS, 크기 (width, height)
out = cv2.VideoWriter('remove.avi', fourcc, fps, (width, height))
window = cv2.resize(window, (width, height)) # width, height 고정 크기


while cap.isOpened():
    ret, frame = cap.read()
    
    if not ret:
        break
    
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, lower_green, upper_green) # 사이에 있는 놈들을 마스크로 만들어라
    mask_inv = cv2.bitwise_not(mask) # 마스크를 거꾸로만들어라
    
    bg = cv2.bitwise_and(frame, frame, mask=mask) # lg와 ug 사이 놈들을 마스크 사이놈들만 살린다
    fg = cv2.bitwise_and(frame, frame, mask=mask_inv) # 위에거의 반대
    
    window_bg = cv2.bitwise_and(window, window, mask=mask) 
    
    result = cv2.addWeighted(src1 = fg, src2=window_bg, alpha=1, beta=1, gamma=0)
    
    if not ret:
        break
    
    out.write(result) # 영상 데이터만 저장 (소리 X)
    cv2.imshow('video', result)
    
        
out.release() # 자원 해제
cap.release()
cv2.destroyAllWindows()

위에서 설정한 범위에 따라서 영상을 저장한다

 

1. ANOVA란?

ANalysis Of VAriance의 약자로 한국말로 직역하면 분산분석이다.

anova는 2개이상의 그룹의 평균을 비교하는 방법이다.

정규분포로부터 생성한 다음 예를 활용해서 설명을 지속하겠다.

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

from scipy import stats

rvs1 = np.random.normal(1,1,100)
rvs2 = np.random.normal(3,1,100)
rvs3 = np.random.normal(5,1,100)

mean1, std1, size1 = np.mean(rvs1), np.std(rvs1), len(rvs1)
print(f'data1  mean : {mean1:0.2f}, std: {std1:0.2f}, size : {size1}')
mean2, std2, size2 = np.mean(rvs2), np.std(rvs2), len(rvs2)
print(f'data2  mean : {mean2:0.2f}, std: {std2:0.2f}, size : {size2}')
mean3, std3, size3 = np.mean(rvs3), np.std(rvs3), len(rvs3)
print(f'data2  mean : {mean3:0.2f}, std: {std3:0.2f}, size : {size3}')


plt.figure(figsize = (10, 5))
sns.kdeplot(data = rvs1, color = 'red', shade = True)
sns.kdeplot(data = rvs2, color = 'blue', shade = True)
sns.kdeplot(data = rvs3, color = 'green', shade = True)
plt.show()
data1  mean : 0.81, std: 1.01, size : 100
data2  mean : 3.09, std: 0.96, size : 100
data2  mean : 4.92, std: 1.04, size : 100

1번그래프

 

rvs_total =np.concatenate((rvs1, rvs2, rvs3))
plt.figure(figsize = (10, 5))
sns.kdeplot(data = rvs_total, color = 'purple', shade = True)
plt.show()

2번그래프

2번그래프를 보면 하나의 집단이지만 각각 다른 수준으로 보면 1번그래프의 모양을 띈다.

anova는 이러한 그룹간의 평균을 비교하여 통계적으로 그룹끼리 다른지 유사한지 알아내기를 도와준다.

 

anova의 결과는 f통계량이다.

정규분포를 제곱하면 chisq분포가 된다. 정규분포는 평균을 추정하는데 사용하고 평균에 제곱이 들어가는 다른 통계값은 분산이다. 정규분포를 제곱한 chisq분포는 분산을 추정하는데에 사용한다.

F분포는 두가지의 chisq분포를 분자와 분모로 나눈 값이다.

다시말하면 분산의 비를 추정할 수 있는 분포이다.

 

anova에서는 집단간의 분산 / 집단내의 분산 으로 집단간의 이질성을 검정한다.

집단 내의 동질성이 늘어나고 집단간의 분산이 커지면  F통계량은 커질것이며 이것은 귀무가설을 강하게 반하는 결과를 가져오게된다.

 

귀무가설(H0) : 그룹이나 평균 간에 차이가 없다.

대립가설(H1) : 집단의 평균 사이에 차이가 있다.

 

 

2. 분산분석의 가정

  • 독립성: 한 관측치에 대한 종속 변수 값은 다른 관측치 값과 독립
  • 종속 변수의 값이 정규 분포를 따릅니다.
  • 등분산성 
  • 종속 변수는 연속적.

저번 포스팅에서 사용했던 levene_test와 norm_test를 그대로 사용해서 각각 확인하면된다.

https://gwoolab.tistory.com/39

 

[통계] t-test

1. T-분포란 - 표본평균으로 정규분포를 따르는 모집단의 평균을 해석할 때 사용 - 모집단의 분산이 알려져 있지 않은 경우에 정규분포 대신 이용하는 확률분포 - 정규분포 보다 두꺼운 꼬리 - 일

gwoolab.tistory.com

 

3. 분산분석의 종류와 실습

- 일원배치분산분석

scipy 이용

anova_one = stats.f_oneway(rvs1, rvs2, rvs3)

print('oneway anova F-statistic = %6.3f pvalue = %6.4f' % anova_one )
oneway anova F-statistic = 354.784 pvalue = 0.0000

pvalue가 0에 가까운 값이기에 귀무가설을 기각한다. 즉 최소 한가지에 그룹이 다른 그룹의 평균과는 다르다

 

statsmodel 이용

import statsmodels.api as sm 
from statsmodels.formula.api import ols 

model = ols('value ~ C(group)', data=anova_df).fit() 
sm.stats.anova_lm(model, typ=1)
  df sum_sq mean_sq F PR(>F)
C(group) 2.0 709.583707 354.791854 354.784462 1.914565e-79
Residual 297.0 297.006187 1.000021 NaN NaN

statsmodel은 좀 더 자세한 결과를 보여줍니다.

연산의 결과는 같음

 

위의 결과에 따르면 그룹에 따라 값이 영향을 받는다고 할 수 있다.

 

- 이원배치분산분석

penguin = sns.load_dataset('penguins')
penguin = penguin[['species','sex','body_mass_g']].dropna()
penguin.head()
  species sex body_mass_g
0 Adelie Male 3,750.0000
1 Adelie Female 3,800.0000
2 Adelie Female 3,250.0000
4 Adelie Female 3,450.0000
5 Adelie Male 3,650.0000

펭귄의 종과 성별에 따라서 몸무게가 영향을 받는지를 검정하고자한다.

 

model = ols('body_mass_g ~ C(species)+C(sex)+C(species):C(sex)', penguin).fit()
result = sm.stats.anova_lm(model, typ=1)

pd.options.display.float_format = '{:,.4f}'.format
# pd.options.display.float_format = '{:.2e}'.format

result
  df sum_sq mean_sq F PR(>F)
C(species) 2.0000 145,190,219.1132 72,595,109.5566 758.3581 0.0000
C(sex) 1.0000 37,090,261.7815 37,090,261.7815 387.4600 0.0000
C(species):C(sex) 2.0000 1,676,556.7364 838,278.3682 8.7570 0.0002
Residual 327.0000 31,302,628.2847 95,726.6920 NaN NaN

formula 부분에서 C(species):C(sex)는 두 변수의 교호작용을 의미한다.

 

모든 pvalue와 F값이 귀무가설을 기각하고 있다.

 

즉 펭귄의 종, 펭귄의 성별에 따라서 펭귄의 몸무게 차이가 유의하다 즉 영향을 준다라고 할 수 있고

교호작용 텀도 유의한 것으로 보아 종이 몸무게에 미치는 영향력의 크기가 성별에 따라서 달랒 질 수 있다는 것을 의미한다

4. etc

ANOVA는 최소 두 그룹의 평균 간에 유의한 차이가 있는지 여부만 알 수 있지만 평균이 다른 쌍은 설명할 수 없다. 

데이터가 정규 곡선에 분포하지 않고 이상값이 있는 경우 검정의 결론이 부정확할 수 있다.

표준편차의 차이가 크면 검정의 결론이 부정확할 수 있다.

 

ANOVA는 모델의 복잡성을 줄이기 위해 입력 변수의 수를 최소화한다.

ANOVA는 독립 변수가 대상 변수에 영향을 미치는지 여부를 결정하는 데 도움이 된다.

 

또한 그룹간의 평균이 다른지 아닌지만을 아렬주고 어떤 그룹의 평균이 큰지에 대한 내용은 제공하지않기때문에 

사후분석이 수반되기도한다.

 

'통계' 카테고리의 다른 글

[통계] 로지스틱 회귀분석  (0) 2022.03.10
[통계] 단순선형회귀분석, 모형진단, 영향점분석  (0) 2022.03.04
[통계] 상관분석  (0) 2022.03.03
[통계] t-test  (0) 2022.02.23
[통계] 가설과 p- value  (0) 2022.02.22

1. T-분포란

 

- 표본평균으로 정규분포를 따르는 모집단의 평균을 해석할 때 사용

- 모집단의 분산이 알려져 있지 않은 경우에 정규분포 대신 이용하는 확률분포

- 정규분포 보다 두꺼운 꼬리

- 일반적으로 n이 30이상이면 중심극한정리에 의해 정규분포로 취급한다.

 

2. T- test의 가정

t-test는 종류마다 각각의 가정을 가지지만 공통적으로 적용되는 것이 있다.

표본이 정규성을 띄느냐 인데 t분포라고 가정을 하고 들어가기때문에 t분포라고 가정할 수 있느냐를 정규성검정으로 확인하는 과정이라고 할 수 있다. (t분포 자체가 정규분포에서 나온 것이기 때문에)

- 정규성검정

 

실습을 위한 데이터 생성

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

from scipy import stats


rvs1 = np.random.normal(10,1,100)
rvs2 = np.random.normal(11,1,100)

mean1, std1, size1 = np.mean(rvs1), np.std(rvs1), len(rvs1)
print(f'data1  mean : {mean1:0.2f}, std: {std1:0.2f}, size : {size1}')
mean2, std2, size2 = np.mean(rvs2), np.std(rvs2), len(rvs2)
print(f'data2  mean : {mean2:0.2f}, std: {std2:0.2f}, size : {size2}')

plt.figure(figsize = (10, 5))
sns.kdeplot(data = rvs1, color = 'red', shade = True)
sns.kdeplot(data = rvs2, color = 'blue', shade = True)
plt.show()
data1  mean : 10.09, std: 0.99, size : 100
data2  mean : 10.98, std: 0.96, size : 100

rvs1은 평균이 10 표준편차가 1인 정규분포에서 100개를 샘플링한값

rvs2은 평균이 11 표준편차가 1인 정규분포에서 100개를 샘플링한값 이다.

 

정규성검정

def norm_test(dist):
    fig, axes= plt.subplots(1,2)
    plt.figure(figsize = (7, 7))
    stats.probplot(dist, dist=stats.norm, plot = axes[0])
    sns.distplot(dist, ax=axes[1])
    plt.show()
    
    print('null hypothesis : Data is a normal distribution.\n')
    
    len_ = len(dist)
    ks_dist = dist - np.mean(dist)
    ks_test = stats.kstest(ks_dist,'norm', N = len_)
    print('*** Kolmogorov-Smirnov test *** \n t-statistic = %6.3f pvalue = %6.4f\n' % ks_test)

    shapiro_test = stats.shapiro(dist)
    print('*** shapiro-Wilk test *** \n t-statistic = %6.3f pvalue = %6.4f' % shapiro_test)
    
    
    
 norm_test(rvs1)

null hypothesis : Data is a normal distribution.

*** Kolmogorov-Smirnov test *** 
 t-statistic =  0.048 pvalue = 0.9688

*** shapiro-Wilk test *** 
 t-statistic =  0.992 pvalue = 0.8079

좌측에 보이는 그래프는 R에서 사용했던 노말qq플롯이다 좌하단과 우상단의 모서리를 잇는 빨간대각선에 비슷하게 파란점들이 위치하면 정규성을 띈다고 할 수 있다.

 

Kolmogorov-Smirnov test와 shapiro-Wilk test 모두 정규성을 검정하는 통계적 방법인데

두 검증 모두 데이터가 정규성을 띈다라는 귀무가설을 가지고 있다.

 

보통쓰이는 유의수준인 0.05를 적용한다면 두 테스트의 결과 모두 귀무가설을 기각할 충분한 근거가 없다.

 

즉 정규성을 만족한다.

 

 

 

3. T -test의 종류 및 실습

 

- 일표본 t검정 one sample T-test

one_sample_ttest = stats.ttest_1samp(rvs1, 10, axis=0,  alternative='two-sided')
print('one sample t-statistic = %6.3f pvalue = %6.4f' % one_sample_ttest )
one sample t-statistic = -0.597 pvalue = 0.5516
 

stats.ttest_1samp(데이터, mu1, axis=0,  alternative='two-sided')

alternative : 'two-sided', 'less', 'greater' 중 선택 (대립가설)

 

rvs1이라는 데이터의 모평균이 10이아니다 라는 대립가설에 대한 가설 검정을 실시한 코드이다.

p-value가 0.55로 모평균이 10이라는 귀무가설을 기각할 충분한 근거가 없다는 검정 결과이다.

즉 모평균이 10일것이라고 말하고 있다.

 

단측검정을 실시한다면 alternative의 옵션을 달리하면된다.

less로 설정한다면 대립가설은 mu < mu1

greater로 설정한다면 대립가설은 mu > mu1

가 될 것이다.

 

 

- two sample t-test

두 데이터의 평균차에 대한 검정입니다. 

먼저 두 데이터의 분산이 같은지(통계적으로 비슷한지)에 따라서 검정을 수행할 때의 수식이 달라지기 때문에 (합동 표본표준편차를 이용한다거나)

등분산 검정을 먼저 실시하고 어떤 옵션으로 실시할지를 결정한다.

levene_test = stats.levene(rvs1, rvs2)
print('null hypothesis : populations have equal variances.')
print('levene test t-statistic = %6.3f pvalue = %6.4f' % levene_test )
null hypothesis : populations have equal variances.
levene test t-statistic =  0.007 pvalue = 0.9342

levene_test는 두 데이터의 등분산성을 검정하는 검정이고 귀무가설은 두데이터가 등분산성을 띈다이다.

pvalue가 0.05보다 높기때문에 두 데이터는 등분산성을 띈다고 할 수 있다.

 

  - 등분산의 경우

var_equal_ttest = stats.ttest_ind(rvs1,rvs2, equal_var = True, alternative = 'two-sided')
print('variance equal t-statistic = %6.3f pvalue = %6.4f' % var_equal_ttest )
variance equal t-statistic = -6.433 pvalue = 0.0000

pvalue가 아주 작은 수준이므로 귀무가설은 기각한다. 즉 두 모평균은 다르다

 

 

- 이분산의 경우

non_equal_ttest = stats.ttest_ind(rvs1,rvs2, equal_var = False, alternative = 'two-sided')
print('non equal t-statistic = %6.3f pvalue = %6.4f' % non_equal_ttest )

등분산 검정에서 서로 분산이 다르다는 검정결과가 나왔을 경우 위 코드를 활요하면된다.

 

만약 이표본 데이터 검정시 두평균이 같은지가 아니라 평균이 a만큼 차이난다를 검중하고 싶다면 한 데이터에 상수 a를 더하면 수행이 가능하다.

두 모평균의 차이가 1일 것이라는 귀무가설을 기각하지 못한다.

실제로 두 모평균의 차이는 1이었다.

 

대립가설의 옵션은 일표본ttest와 같은 방법으로 적용된다.

 

 

  - paired T-test 

순서별로 쌍을 이룬 데이터로 고려하여 두 데이터의 평균차를 검정한다.

실제 예를 든다면 

 

 동일한 피실험자들에 대한 처치 이전 이후를 확인하는 경우이다.

다이어트 약의 효과를 보기 위해 먹기전의 몸무게 먹은후의 몸무게가 이 예가 될 수 있겠다. 물론 다른 조건은 동일하게 줘야한다.

bias = np.random.normal(1,1,100)
bias[np.where(bias<0)] = 0
rvs1_bias = rvs1 + bias

non_equal_ttest = stats.ttest_rel(rvs1,rvs1_bias)
print('paired t-statistic = %6.3f pvalue = %6.4f' % non_equal_ttest )
paired t-statistic = -11.551 pvalue = 0.0000

rvs1에 양수 or 0을 더한 값을 처치 이후로 가정하고 검정을 실시하였다.

 

pvalue가 아주 작은 값을 가지기때문에 처치이전과 이후의 모평균에는 유의미한 차이가 있다고 할 수 있다.

이 경우에도 대립가설의 수정과 a만큼의 차이는 위의 이표본,일표본의 경우와 같게 적용 가능하다.

 

 

 

 

'통계' 카테고리의 다른 글

[통계] 로지스틱 회귀분석  (0) 2022.03.10
[통계] 단순선형회귀분석, 모형진단, 영향점분석  (0) 2022.03.04
[통계] 상관분석  (0) 2022.03.03
[통계] ANOVA 분산분석  (0) 2022.02.23
[통계] 가설과 p- value  (0) 2022.02.22

1. 순열

import itertools


color_list = ['red','blue','green']

nPr = itertools.permutations(color_list, 2)
print(list(nPr))
[('red', 'blue'), ('red', 'green'), ('blue', 'red'), ('blue', 'green'), ('green', 'red'), ('green', 'blue')]

순서를 고려하여 즉 (a,b)와 (b,a)를 다른 것으로 치고 뽑기 

itertools.permutations(list, n)

list에서 n개를 뽑는경우

 

 

2. 조합

nCr = itertools.combinations(color_list, 2)
print(list(nCr))
[('red', 'blue'), ('red', 'green'), ('red', 'orange'), ('blue', 'green'), ('blue', 'orange'), ('green', 'orange')]

순서를 고려하여 즉 (a,b)와 (b,a)를 같은 것으로 치고 뽑기

itertools.combinations(list, n)

list에서 n개를 뽑는경우

 

 

pandas

import pandas as pd

 

- 빅데이터 연산의 기초

- 데이터 구조를 정의

- numpy와 같은 타 모듈과의 전환이 용이

- pd라고 alias를 정의해 빠르게 사용 다른 alias를 지정해도 사용에는 무방하나 pd로 칭하는게 암묵적인 룰

 

 

시리즈란

- 파이썬기본 데이터유형인 딕셔너리와 유사한형태

- index : value 형태로 이루어진 데이터 

- 집계연산의 편의, 인덱싱의 편의

- 시리즈를 결합하면 데이터프레임이됨

- 데이터프레임에서 그룹 연산시 산출물이 시리즈로 제공되기 때문에 알고있어야 도움

 

생성

series1 = pd.Series({'국어':100, '수학':90, '영어':80})
series2 = pd.Series([100,20,45,90,100,87,45], index = ['k','e','a','b','f','c','d'])
series3 = pd.Series([100,20,45,90,100,87,45])
print(series1)
print('-'*30)
print(series2)
print('-'*30)
print(series3)
국어    100
수학     90
영어     80
dtype: int64
------------------------------
k    100
e     20
a     45
b     90
f    100
c     87
d     45
dtype: int64
------------------------------
0    100
1     20
2     45
3     90
4    100
5     87
6     45
dtype: int64

value와 인덱스를 지정하여 생성가능 인덱스를 지정하지 않을시 0에서 시작하는 정수로 순서대로 임의의 인덱스 부여

딕셔너리와 유사한 형태이기때문에 딕셔너리로 생성도 가능

 

 

인덱싱과 슬라이싱

두가지 방법으로 가능 해당하는 인덱스로 / 위치로

 

print(series2)
print('-'*30)

# 인덱스로 인덱싱 혹은 슬라이싱
print(series2['k'])
print('-'*30)
print(series2['k':'a'])
print('-'*30)

# 위치로 
print(series2.iloc[1])
print('-'*30)
print(series2.iloc[:1])
k    100
e     20
a     45
b     90
f    100
c     87
d     45
dtype: int64
------------------------------
100
------------------------------
k    100
e     20
a     45
dtype: int64
------------------------------
20
------------------------------
k    100
dtype: int64

인덱싱시 해당하는 인덱스에 속한 밸류를 반환한다.

슬라이싱시 해당하는 범위의 시리즈를 반환한다.

 

iloc을 이용할시 위치에 따라 인덱싱과 슬라이싱이 가능하다 1번째 값은(파이썬은 0부터시작) 20이기에 20을 반환

iloc[:1] 은 1번째 전까지의 녀석을 시리즈로 반환한다.

 

series2[['a','b','d']]
a    45
b    90
d    45
dtype: int64

이렇게 원하는녀석들만 볼 수도있다.

 

불리언 인덱싱

print((90>=series2) & (series2>50))
print('-'*30)
print(series2.loc[(90>=series2) & (series2>50)])
k    False
e    False
a    False
b     True
f    False
c     True
d    False
dtype: bool
------------------------------
b    90
c    87
dtype: int64

시리즈의 밸류에 관하여 불리언 연산이 가능하고 

그 불리언의 트루에 해당하는값만을 슬라이싱 가능하다.

 

print(series2.loc[(series2.index > 'b').tolist()])
k    100
e     20
f    100
c     87
d     45
dtype: int64

이런식으로 한다면 인덱스의 불리언 연산도 가능하다.

따로 기능이있는지는 잘모르겠다

 

시리즈 정렬

print(series2.sort_values())
print('-'*30)
print(series2.sort_values(ascending = False))
e     20
a     45
d     45
c     87
b     90
k    100
f    100
dtype: int64
------------------------------
k    100
f    100
b     90
c     87
a     45
d     45
e     20
dtype: int64

시리즈의 값을 기준으로 정렬을 할 수 있다. ascending을 False로 설정하면 내림차순으로 정렬된다.

print(series2.sort_index())
print('-'*30)
print(series2.sort_index(ascending = False))
a     45
b     90
c     87
d     45
e     20
f    100
k    100
dtype: int64
------------------------------
k    100
f    100
e     20
d     45
c     87
b     90
a     45
dtype: int64

인덱스를 기준으로도 거의 동일하게 정렬이 가능하다.

 

갯수세기

series2.value_counts()
100    2
45     2
20     1
90     1
87     1
dtype: int64

밸류의 갯수세기도 가능하다

인덱스는 보통 유일한 값을 가지기때문에 인덱스에 대한 물음은 가지지않았다.

 

간단한 연산

print(series2.mean())
print(series2.max())
print(series2.min())
print(series2.median())
69.57142857142857
100
20
87.0

 

딕셔너리

- 키 : 밸류 형태

- pandas와 큰 연관

- 머신러닝 파라미터적용시 많이 사용

- 리스트와 같이 가장많이 쓰이는 집합자료형

 

생성

dict1 = {'국어':100, '수학':90, '영어':80}
print(dict1)
dict1['국어'] = 95
dict1['통계'] = 100
print(dict1)
k = dict1.pop('통계')
print(dict1)
print(k) # 밸류가 나온다
{'국어': 100, '수학': 90, '영어': 80}
{'국어': 95, '수학': 90, '영어': 80, '통계': 100}
{'국어': 95, '수학': 90, '영어': 80}
100

인덱싱은 key를 이용해서 가능하고 새로운 key:value도 인덱싱을 사용하여 삽입가능하다.

pop 또한 key를 이용하고 뽑아낸 원소는 value가 반환된다.

슬라이싱은 불가능하다.

 

물론 문자:숫자가 아닌 다른 경우도 가능하다

 

 

keys , values, items

print(list(dict1.keys()))
print(list(dict1.values()))
print(list(dict1.items()))
print(list(dict1.items())[0])
['국어', '수학', '영어']
[95, 90, 80]
[('국어', 95), ('수학', 90), ('영어', 80)]
('국어', 95)

keys 는 key들을 반환한다.

values 는 value들을  반환한다.

items 는 key,value를 튜플로 묶은 쌍들을 반환한다.

for key, value in dict1.items():
    print('{}점수는 {}점 입니다'.format(key,value))
국어점수는 95점 입니다
수학점수는 90점 입니다
영어점수는 80점 입니다

이런 식으로 응용가능하다.

 

추후 게시할 pandas에 행을 추가할 때 주로 딕셔너리를 이용하기 때문에 잘 알아아 둘 필요가 있다.

 

 

in

print('국어' in dict1)
print('과학' in dict1)
True
False

 

get

print(dict1['과학'])
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-32-1a2cdb189a8b> in <module>
----> 1 print(dict1['과학'])

KeyError: '과학'

일반 인덱싱을 이용하면 오류

print(dict1.get('과학'))
print(dict1.get('과학',0))
None
0

get을 이용하면 none 혹은 디폴트로 지정한 녀석을 반환한다.

 

이를 응용하면 카운트할 때 쉽다.

c_list = ['a','a','c','c','c','a','a','c','a','a','a','b','b','b','b']

count_dic = {}
for spel in c_list:
    count_dic[spel] = count_dic.get(spel, 0) + 1
print(count_dic)
{'a': 7, 'c': 4, 'b': 4}

물론 리스트의 count기능을 사용할 수 있지만 리스트의 길이 혹은 문자열의 길이가 셀수없이 길어진다면 모든 경우를 카운트하기에는 무리가 있다. 

 

'python 기초' 카테고리의 다른 글

[python기초] tqdm for문 예상속도, time  (0) 2021.12.06
[ python 기초 ] lambda, map, filter  (0) 2021.08.27
[ python 기초 ] 셋 set  (0) 2021.08.19
[ python 기초 ] 튜플 tuple  (0) 2021.08.19
[ python 기초 ] 리스트 list  (1) 2021.08.19

 

- 중복을 허용하지 않고 

- 인덱싱과 슬라이싱 불가능

- 집합연산 용이

 

생성

set1 = {'a','b','c','d','e'}
print(set1)

set2 = {'a','b','c','d','e','a','a','g','k'}
print(set2)
{'c', 'b', 'a', 'd', 'e'}
{'c', 'g', 'b', 'a', 'd', 'k', 'e'}

 

{} 로 생성한다. 셋을 생성하면 중복된 원소들은 제거된다.

 

 

인덱스 슬라이스 불가

set1[0]
set1[:2]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-c38563f1af7a> in <module>
----> 1 set1[0]

TypeError: 'set' object is not subscriptable

불가능하다.

 

집합연산

set1 = {'a','b','c','d','e'}
set2= {'c','d','e','f','g'}


print('set1',set1)
print('set2',set2)
print('교집합 ',set1&set2)
print('합집합 ',set1|set2)
print('차집합 ',set2-set1)
print('합집합 - 교집합 ',set1^set2)
{'c', 'b', 'a', 'd', 'e'}
{'c', 'g', 'd', 'f', 'e'}
set1 {'c', 'b', 'a', 'd', 'e'}
set2 {'c', 'g', 'd', 'f', 'e'}
교집합  {'c', 'e', 'd'}
합집합  {'c', 'g', 'b', 'a', 'd', 'f', 'e'}
차집합  {'g', 'f'}
합집합 - 교집합  {'g', 'f', 'b', 'a'}

 

보통 중복을 없애는데 사용한다

튜플

 

- 값의 수정이나 변경, 추가, 제거가 불가능하다. 변경 불가능한 리스트라고 이해

- 하지만 리스트에서 튜플 튜플에서 리스트로 변경은 가능

- 인덱싱 슬라이싱 리스트와 동일

- 모듈이나 기본함수의 출력값의 형식으로 많이 산출됨 

 

생성

tuple_ = ('a','b','c','d')
print(tuple_)
('a', 'b', 'c', 'd')

인덱싱, 슬라이싱

print(tuple_[2])
print(tuple_[-1])
print(tuple_[:2])
print(tuple_[::-1])
c
d
('a', 'b')
('d', 'c', 'b', 'a')

리스트와 동일하게 인덱싱 슬라이싱 가능하고 슬라이싱의 결과는 튜플 형태로 출력된다.

 

수정 및 추가

tuple_[0] = 'A'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-72-c25b0f105887> in <module>
----> 1 tuple_[0] = 'A'

TypeError: 'tuple' object does not support item assignment

수정 및 추가 삭제가 불가능하다.

 

리스트로의 변환을 활용한 추가, 제거

words = ['apple', 'banana', 'python', 'list', 'woo','woo','Java', 'won']

tuple_2 = tuple(words)
print(tuple_2, type(tuple_2), sep='  /  ')
tuple_2 = list(tuple_2)
print(tuple_2, type(tuple_2), sep='  /  ')
tuple_2.append('g')
tuple_2 = tuple(tuple_2)
print(tuple_2, type(tuple_2), sep='  /  ')
('apple', 'banana', 'python', 'list', 'hye', 'woo', 'Java', 'won')  /  <class 'tuple'>
['apple', 'banana', 'python', 'list', 'hye', 'woo', 'Java', 'won']  /  <class 'list'>
('apple', 'banana', 'python', 'list', 'hye', 'woo', 'Java', 'won', 'g')  /  <class 'tuple'>

변경을 원하는 경우에는 먼저 리스트로 형변환 이후에 변경하고 다시 튜플로 변환하면 가능하다 

 

index, count

words = ('apple', 'banana', 'python', 'list', 'woo','woo','Java', 'won')


print('apple' in words)
print('grape' in words)

print(words.index('apple'))
print(words.count('woo'))
True
False
0
2

 

함수의 결과

nums = [3,56,6,2]

def base_stat(list_):
    return max(list_),min(list_)

base_stat(nums)
(56, 2)

튜플의 변경이 불가능하다는 특성 때문인지 함수의 반환결과는 튜플로 반환되는 경우가 많습니다.

import pandas as pd
df = pd.read_csv('address.csv')
df.shape
(3042, 2)

리스트란

 

- 파이썬 기본 자료구조 형태중 하나

- 값을 나열한 것

- 시퀀스데이터 (자료의 순서가 있는 것)

- 자료의 변경, 삭제 , 추가가 자유로움.

 

리스트만들기

letters1 = ['a','b','c']
letters2 = ['d','e','f']

리스트명 = [ 원소1, 원소2, 원소3 , ... ]

위와 같이

 

리스트명 = [ 원소1, 원소2, 원소3 , ... ] 이런 형식으로 리스트를 생성할 수 있다.

내부원소의 자료형이 통일될 필요는 없다.

 

리스트 인덱싱

원소 a b c d e
인덱스 0 1 2 3 4
letters1 = ['a','b','c','d','e']
print(letters1[0])
print(letters1[1])
print(letters1[2])

letters1[0] = 3
print(letters1)
a
b
c

[3, 'b', 'c', 'd', 'e']

파이썬 리스트의 인덱스는 0부터  시작하며 첫 원소부터 차례대로 대응된다.

만약 print(letters1[3]) 

이와 같이 리스트에 없는 인덱스의 원소를 요청했다면 오류가 발생된다.

 

인덱싱을 활용하면 자료의 변경이 쉽게 가능하다.

 

 

 

리스트 슬라이싱

print(letters1[:3])  # 처음부터 3번 원소 전까지
print(letters1[2:])  # 2번 원소 전부터 끝까지
print(letters1[2:3]) # 2번 원소 전부터 3번원소 전까지
print(letters1[2:3][0]) # 원소에 직접접근하려면

print(letters1[::2]) # 처음부터 끝까지 2칸씩 띄워서 홀수 번째 친구들 
print(letters1[1::2]) # 1번원소 전부터 끝까지 2칸씩 띄워서 짝수 번째 친구들
['a', 'b', 'c']
['c', 'd', 'e']
['c']
c

['a', 'c', 'e']
['b', 'd']

리스트의 일부를 잘라 리스트로 반환한다. 

 

이때 중요한 점은 리스트로 반환한다는 점이다. 

3번째 경우 슬라이싱의 결과도 원소의 갯수가 1인 리스트로 반환이 되기 때문에 원소에 직접 접근하고 싶다면 

4번째줄의 코드와 같이 인덱싱을 진행해주어야한다.

 

 

다중리스트

리스트안에 리스트가 있는경우

letters1 = ['a','b','c','d','e']
letters2 = [letters1, 'f', 'g']
print(letters2)
print(letters2[0][2])
[['a', 'b', 'c', 'd', 'e'], 'f', 'g']
c
원소 ['a', 'b', 'c', 'd', 'e'] f g
인덱스 0 1 2

c에 접근하고싶다면 먼저 letters2의 첫번째 원소인 letters1에  접근하고 해당 리스트에서 인덱스로 접근한다.

 

 

 

 

리스트 함수 

 

1. len

print(len(letters1))
print(len(letters2))
5
3

리스트의 길이를 반환해준다. 

다중리스트의 경우 내부리스트가 얼마나 길든 1로 계산한다.

 

2. 리스트 이어붙이기

letters1 = ['a','b','c']
letters2 = ['d','e','f']

print(letters1 + letters2)

nums1 = [1,2,3]
nums2 = [4,5,6]
print(nums1 + nums2)

print(nums1 * 3)
['a', 'b', 'c', 'd', 'e', 'f']
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 1, 2, 3, 1, 2, 3]

더하기 연산자로 이을 수 있다.

모든 원소가 숫자인 리스트도 각 인덱스에 대응하는 원소끼리의 연산이 아닌 두 리스트를 이은 리스트가 반환된다.

 

곱하기 연산자를 사용할 경우 곱하는 숫자만큼 리스트의 원소를 반복한 뒤 반환한다.

 

3. in

print('a' in letters1)
print('A' in letters1)
print('a' in letters2)
True
False
False

리스트에 해당하는 원소가 있으면 True 없으면 FALSE를 반환한다.

파이썬은 대소문자를 구분한다.

letters2에는 'a'가 있어보이지만 letters2에 있는 letters1에 a가 존재하는 것이다.

 

 

4. count

letters3 = ['a','a','b']
letters3.count('a')
2

리스트내의 일치하는 원소의 갯수를 세어준다

5. append

print(letters1)
letters1.append('f')
print(letters1)
['a', 'b', 'c']
['a', 'b', 'c', 'f']

리스트의 맨뒤에 새로운 원소를 삽입한다.

nums1 = [1,2,3]
nums2 = [4,5,6]
result = []

for i in range(len(nums1)):
    result.append(nums1[i]+nums2[i])
print(result)
[5, 7, 9]

이런식으로 빈리스트에 새로운 값들을 추가할 수도있다.

 

6. insert

맨뒤에 값을 추가하는 append와는 다르게 insert는 원하는 위치에 값을 삽입할 수 있다.

print(letters1)
letters1.insert(1,'A')
print(letters1)
['a', 'b', 'c', 'd', 'e']
['a', 'A', 'b', 'c', 'd', 'e']

7. pop 

print(letters1)
k = letters1.pop(1)
print(letters1)
print(k)
['a', 'A', 'b', 'c', 'd', 'e']
['a', 'b', 'c', 'd', 'e']
A

원하는 인덱스의 값을 빼내어 준다. 빼낸값을 저장할 수도 있다.

인덱스를 입력하지 않으면 제일 뒤의 값을 빼내어 준다.

이런식으로 값이 순환하게 할 수도 있다.

print(letters1)
k = letters1.pop(0)
letters1.append(k)
print(letters1)
['a', 'b', 'c', 'd', 'e']
['b', 'c', 'd', 'e', 'a']

 

8. remove

print(letters1)
letters1.remove('b')
print(letters1)
['a', 'b', 'c', 'd', 'e']
['a', 'c', 'd', 'e']

해당하는 원소를 삭제한다.

 

9. sort

nums = [5, 2, 22, 4, 5, 3, 7, 1]
words = ['apple', 'banana', 'python', 'list', 'woo','Java', 'won']

nums.sort()  #정수 정렬
words.sort()     #문자열 정렬

print(nums)
print(words)

nums.sort(reverse=True)  #정수 정렬
words.sort(reverse=True)     #문자열 정렬

print(nums)
print(words)
[1, 2, 3, 4, 5, 5, 7, 22]
['Java', 'apple', 'banana', 'list', 'python', 'won', 'woo']
[22, 7, 5, 5, 4, 3, 2, 1]
['woo', 'won', 'python', 'list', 'banana', 'apple', 'Java']

리스트 내의 원소들을 정렬하여 반환한다. 기본값은 오름차순이다.

 

 

 

10. reverse

words = ['apple', 'banana', 'python', 'list', 'woo','Java', 'won']
print(words)
words.reverse()
print(words)
['apple', 'banana', 'python', 'list', 'woo', 'Java', 'won']
['won', 'Java', 'woo', 'list', 'python', 'banana', 'apple']

리스트의 원소의 순서를 뒤집어 반환한다.

 

11. index

words = ['apple', 'banana', 'python', 'list', 'woo','woo','Java', 'won']
print(words.index('woo'))

words[words.index('woo')] = 'hye'
print(words)
4
['apple', 'banana', 'python', 'list', 'hye', 'woo', 'Java', 'won']

리스트안에 일치하는 원소의 첫번째 인덱스를 반환한다.

산출된 인덱스를 이용해서 원소를 변경도 가능하다.

리스트안에 일치하는 원소가 없다면 오류를 반환한다.

+ Recent posts