RandomForest

 : 앙상블 기법(여러개의 Decision Tree를 묶어 하나의 모델로 사용)

 : 정량적인 분석 모델

 

RandomForestClassifier 분류 모델 연습

 

 * randomForest1.py

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
import pandas as pd
from sklearn import model_selection
import numpy as np
from sklearn.metrics._scorer import accuracy_scorer

df = pd.read_csv('https://raw.githubusercontent.com/pykwon/python/master/testdata_utf8/titanic_data.csv')
print(df.head(3), df.shape) # (891, 12)
'''
   PassengerId  Survived  Pclass  ...     Fare Cabin  Embarked
0            1         0       3  ...   7.2500   NaN         S
1            2         1       1  ...  71.2833   C85         C
2            3         1       3  ...   7.9250   NaN         S
'''
print(df.columns)
# Index(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp',
#        'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'],
#       dtype='object')
print(df.info())
 #   Column       Non-Null Count  Dtype  
# ---  ------       --------------  -----  
#  0   PassengerId  891 non-null    int64  
#  1   Survived     891 non-null    int64  
#  2   Pclass       891 non-null    int64  
#  3   Name         891 non-null    object 
#  4   Sex          891 non-null    object 
#  5   Age          714 non-null    float64
#  6   SibSp        891 non-null    int64  
#  7   Parch        891 non-null    int64  
#  8   Ticket       891 non-null    object 
#  9   Fare         891 non-null    float64
#  10  Cabin        204 non-null    object 
#  11  Embarked     889 non-null    object 

print(df.isnull().any())
# PassengerId    False
# Survived       False
# Pclass         False
# Name           False
# Sex            False
# Age             True
# SibSp          False
# Parch          False
# Ticket         False
# Fare           False
# Cabin           True
# Embarked        True

df.isnull().any() : null 값 확인.

 

df = df.dropna(subset=['Pclass','Age','Sex'])
print(df.head(3), df.shape) # (714, 12)

df_x = df[['Pclass','Age','Sex']]
print(df_x.head(3))
'''
   Pclass   Age     Sex
0       3  22.0    male
1       1  38.0  female
2       3  26.0  female
'''

df.dropna(subset=['칼럼1', '칼럼2',..]) : 칼럼에 결측치가 있으면 제거.

 

from sklearn.preprocessing import LabelEncoder, OneHotEncoder

df_x.loc[:, 'Sex'] = LabelEncoder().fit_transform(df_x['Sex']) # female : 0, male : 1
df_x['Sex'] = df_x['Sex'].apply(lambda x: 1 if x=='male' else 0) # 위와 동일

print(df_x.head(3), df_x.shape) # (714, 3)
'''
   Pclass   Age  Sex
0       3  22.0    1
1       1  38.0    0
2       3  26.0    0
'''

df_y = df['Survived']
print(df_y.head(3), df_y.shape) # (714,)
'''
0    0
1    1
2    1
'''

df_x2 = pd.DataFrame(OneHotEncoder().fit_transform(df_x['Pclass'].values[:,np.newaxis]).toarray(),\
                     columns = ['f_class', 's_class', 't_class'], index=df_x.index)
print(df_x2.head(3))
'''
   f_class  s_class  t_class
0      0.0      0.0      1.0
1      1.0      0.0      0.0
2      0.0      0.0      1.0
'''

df_x = pd.concat([df_x, df_x2], axis=1)
print(df_x.head(3))
'''
   Pclass   Age  Sex  f_class  s_class  t_class
0       3  22.0    1      0.0      0.0      1.0
1       1  38.0    0      1.0      0.0      0.0
2       3  26.0    0      0.0      0.0      1.0
'''

from sklearn.preprocessing import LabelEncoder

LabelEncoder().fit_transform(df['범주형 칼럼']) : 범주형 데이터를 수치형으로 변환.

from sklearn.preprocessing import OneHotEncoder

OneHotEncoder().fit_transform(df['칼럼명']).toarray() : One hot encoding

np.newaxis : 차원 증가.

pd.concat([칼럼, .. ], axis=1) : 열 방향 합치기

 

# train / test
(train_x,  test_x, train_y, test_y) = train_test_split(df_x, df_y)

# model
from sklearn.metrics import accuracy_score

model = RandomForestClassifier(n_estimators=500, criterion='entropy')
fit_model = model.fit(train_x, train_y)

pred = fit_model.predict(test_x)
print('예측값:', pred[:10])           # [0 0 0 1 0 0 0 1 0 0]
print('실제값:', test_y[:10].ravel()) # [0 1 0 0 1 0 0 1 0 0]

print('acc :', sum(test_y == pred) / len(test_y))
print('acc :', accuracy_score(test_y, pred))

from sklearn.ensemble import RandomForestClassifier

RandomForestClassifier(n_estimators=100, criterion='entropy') : n_estimators : 트리 수, criterion : 분할 품질 측정 방법.

from sklearn.metrics import accuracy_score

accuracy_score(실제값, 예측값) : 정확도 산출.

ravel() : 차원 축소.

 

 - RandomForestClassifier API

scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html

 

sklearn.ensemble.RandomForestClassifier — scikit-learn 0.24.1 documentation

 

scikit-learn.org


보스톤 지역의 주택 평균가격 예측

 * randomForest_regressor.py

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_boston

boston = load_boston()
print(boston.DESCR)
# MEDV     Median value of owner-occupied homes in $1000's

# DataFrame 값으로 변환
dfx = pd.DataFrame(boston.data, columns = boston.feature_names)
# dataset에서 독립변수 값만 추출
dfy = pd.DataFrame(boston.target, columns = ['MEDV'])
# dataset에서 종속변수 값 추출

print(dfx.head(3), dfx.shape) # (506, 13)
'''
      CRIM    ZN  INDUS  CHAS    NOX  ...  RAD    TAX  PTRATIO       B  LSTAT
0  0.00632  18.0   2.31   0.0  0.538  ...  1.0  296.0     15.3  396.90   4.98
1  0.02731   0.0   7.07   0.0  0.469  ...  2.0  242.0     17.8  396.90   9.14
2  0.02729   0.0   7.07   0.0  0.469  ...  2.0  242.0     17.8  392.83   4.03
'''
print(dfy.head(3), dfy.shape) # (506, 1)
'''
   MEDV
0  24.0
1  21.6
2  34.7 
'''
df = pd.concat([dfx, dfy], axis=1)
print(df.head(3))
'''
      CRIM    ZN  INDUS  CHAS    NOX  ...    TAX  PTRATIO       B  LSTAT  MEDV
0  0.00632  18.0   2.31   0.0  0.538  ...  296.0     15.3  396.90   4.98  24.0
1  0.02731   0.0   7.07   0.0  0.469  ...  242.0     17.8  396.90   9.14  21.6
2  0.02729   0.0   7.07   0.0  0.469  ...  242.0     17.8  392.83   4.03  34.7
'''

from sklearn.datasets import load_boston

load_boston() : boston 부동산관련 dataset.

 

 - 상관계수

pd.set_option('display.max_columns', 100) # 데이터 프레임 출력시 생략 값 출력.
print(df.corr()) # 상관계수 확인
# RM       average number of rooms per dwelling.                   상관계수 : 0.695360
# AGE      proportion of owner-occupied units built prior to 1940. 상관계수 : -0.376955
# LSTAT    % lower status of the population                        상관계수 : -0.737663

pd.set_option('display.max_columns', 100) :데이터 프레임 출력시 컬럼 생략 값 출력.

 

 - 시각화

import seaborn as sns
cols = ['MEDV', 'RM', 'AGE', 'LSTAT']
sns.pairplot(df[cols])
plt.show()

import seaborn as sns

sns.pairplot(데이터) : 변수 간 산점 분포도 출력.

 

 - sklearn에 맞게 데이터 변환

x = df[['LSTAT']].values # sklearn에서 득립변수는 2차원
y = df['MEDV'].values
print(x[:2])             # [[4.98] [9.14]]
print(y[:2])             # [24.  21.6]

 

 - DecisionTreeRegressor

# 실습 1
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import r2_score

model = DecisionTreeRegressor(max_depth=3).fit(x, y)
print('predict :', model.predict(x)[:5]) # predict : [30.47142857 25.84701493 37.315625   43.98888889 30.47142857]
print('real :', y[:5])                   # real : [24.  21.6 34.7 33.4 36.2]
r2 = r2_score(y, model.predict(x))
print('결정계수(R2, 설명력) :', r2)          # 결정계수(R2, 설명력) : 0.6993833085636556

from sklearn.tree import DecisionTreeRegressor

DecisionTreeRegressor(max_depth=).fit(x, y) : 결정 트리 회귀

from sklearn.metrics import r2_score

r2_score(실제값, 예측값) : r square 값 산출

 

 - RandomForestRegressor

# 실습 2
from sklearn.ensemble import RandomForestRegressor

model2 = RandomForestRegressor(n_estimators=1000, criterion='mse', random_state=123).fit(x, y) # criterion='mse' 평균 제곱오차
print('predict2 :', model2.predict(x)[:5]) # predict : [24.7535     22.0408     35.2609581  38.8436     32.00298571]
print('real :', y[:5])                     # real : [24.  21.6 34.7 33.4 36.2]
r2_1 = r2_score(y, model2.predict(x))
print('결정계수(R2, 설명력) :', r2_1)          # 결정계수(R2, 설명력) : 0.9096858991691069

from sklearn.ensemble import RandomForestRegressor

RandomForestRegressor(n_estimators=, criterion='mse', random_state=).fit(x, y) : criterion='mse' 평균 제곱오차

 

 - 학습/검정 자료로 분리

from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=123)
model2.fit(x_train, y_train)

r2_train = r2_score(y_train, model2.predict(x_train))
print('train에 대한 설명력 :', r2_train)  # train에 대한 설명력 : 0.9090659680794153

r2_test = r2_score(y_test, model2.predict(x_test))
print('test에 대한 설명력 :', r2_test)    # test에 대한 설명력 : 0.5779609792473676
# 독립변수의 수를 늘려주면 결과는 개선됨.

from sklearn.model_selection import train_test_split

train_test_split(x, y, test_size=, random_state=) : train/test로 분리

 

 - 시각화

from matplotlib import style 
style.use('seaborn-talk')
plt.scatter(x, y, c='lightgray', label='train data')
plt.scatter(x_test, model2.predict(x_test), c='r', label='predict data, $R^2=%.2f$'%r2_test)
plt.xlabel('LSTAT')
plt.ylabel('MEDV')
plt.legend()
plt.show()

from matplotlib import style

print(plt.style.available) : 사용 가능 스타일 출력.

style.use('스타일명') : matplot 스타일 사용.

 - 새로운 값으로 예측

import numpy as np
print(x_test[:3])                        # [[10.11] [ 6.53] [ 3.76]]
x_new = [[50.11], [26.53], [1.76]]
print('예상 집값 :', model2.predict(x_new)) # 예상 집값 : [ 9.6527  11.0907  45.34095]

 배깅 / 부스팅

 

배깅(Bagging) - Random Forest
  : 데이터에서 여러 bootstrap 자료 생성, 모델링 후 결합하여 최종 예측 모형을 만드는 알고리즘
    boostrap aggregating의 약어로 데이터를 가방(bag)에 쓸어 담아 복원 추출하여 여러 개의 표본을 만들어 이를 기반으로 각각의 모델을 개발한 후에 결과를 하나로 합쳐 하나의 모델을 만들어 내는 것이다. 
    배깅을 통해서 얻을 수 있는 효과는 '알고리즘의 안정성'이다. 
    단일 seed 하나의 값을 기준으로 데이터를 추출하여 모델을 생성해 나는 것보다, 여러 개의 다양한 표본을 사용함으로써 모델을 만드는 것이 모집단을 잘 대표할 수 있게 된다. 
    또한 명목형 변수 (Categorical data)의 경우 투표(voting) 방식, 혹은 가장 높은 확률값으로 예측 결과값을 합치며 연속형 변수(numeric data)의 경우에는 평균(average)으로 값을 집계한다. 
    또한 배깅은 병렬 처리를 사용할 수 있는데, 독립적인 데이터 셋으로 독립된 모델을 만들기 때문에 모델 생성에 있어서 매우 효율적이다.


부스팅(Boosting) - XGBoost
  : 오분류 개체들에 가중치를 적용하여 새로운 분류 규칙 생성 반복 기반 최종 예측 모형 생성
    좀 더 알아보자면 Boosting이란 약한 분류기를 결합하여 강한 분류기를 만드는 과정이다. 
    분류기 A, B, C 가 있고, 각각의 0.3 정도의 accuracy를 보여준다고 하자. 
    A, B, C를 결합하여 더 높은 정확도, 예를 들어 0.7 정도의 accuracy를 얻는 게 앙상블 알고리즘의 기본 원리다. 
    Boosting은 이 과정을 순차적으로 실행한다.
    A 분류기를 만든 후, 그 정보를 바탕으로 B 분류기를 만들고, 다시 그 정보를 바탕으로 C 분류기를 만든다. 
   그리고 최종적으로 만들어진 분류기들을 모두 결합하여 최종 모델을 만드는 것이 Boosting의 원리다. 
   대표적인 알고리즘으로 에이다부스트가 있다. AdaBoost는 Adaptive Boosting의 약자이다. 
   Adaboost는 ensemble-based classifier의 일종으로 weak classifier를 반복적으로 적용해서, data의 특징을 찾아가는 알고리즘.

 

 - anaconda prompt

pip install xgboost

 

 * xgboost1.py

# RandomForest vs xgboost
import pandas as pd
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn import metrics
import numpy as np
import xgboost as xgb       # pip install xgboost  
 
if __name__ == '__main__':
    iris = datasets.load_iris()
    print('아이리스 종류 :', iris.target_names)
    print('데이터 열 이름 :', iris.feature_names)
 
    # iris data로 Dataframe
    data = pd.DataFrame(
        {
            'sepal length': iris.data[:, 0],
            'sepal width': iris.data[:, 1],
            'petal length': iris.data[:, 2],
            'petal width': iris.data[:, 3],
            'species': iris.target
        }
    )
    print(data.head(2))
    '''
           sepal length  sepal width  petal length  petal width  species
    0           5.1          3.5           1.4          0.2        0
    1           4.9          3.0           1.4          0.2        0
    '''
 
    x = data[['sepal length', 'sepal width', 'petal length', 'petal width']]
    y = data['species']
 
    # 테스트 데이터 30%
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=123)
 
    # 학습 진행
    model = RandomForestClassifier(n_estimators=100)  # RandomForestClassifier - Bagging 방법 : 병렬 처리
    model = xgb.XGBClassifier(booster='gbtree', max_depth=4, n_estimators=100) # XGBClassifier - Boosting : 직렬처리
    # 속성 - booster: 의사결정 기반 모형(gbtree), 선형 모형(linear)
    #    - max_depth [기본값: 6]: 과적합 방지를 위해서 사용되며 CV를 사용해서 적절한 값이 제시되어야 하고 보통 3-10 사이 값이 적용된다.

    model.fit(x_train, y_train)
 
    # 예측
    y_pred = model.predict(x_test)
    print('예측값 : ', y_pred[:5])
    # 예측값 :  [1 2 2 1 0]

    print('실제값 : ', np.array(y_test[:5]))
    # 실제값 :  [1 2 2 1 0]
 
    print('정확도 : ', metrics.accuracy_score(y_test, y_pred))
    # 정확도 :  0.9333333333333333

import xgboost as xgb

xgb.XGBClassifier(booster='gbtree', max_depth=, n_estimators=) : XGBoost 분류 - Boosting(직렬처리)
booster : 의사결정 기반 모형(gbtree), 선형 모형(linear)
max_depth : 과적합 방지를 위해서 사용되며 CV를 사용해서 적절한 값이 제시되어야 하고 보통 3-10 사이 값이 적용됨.

(default: 6)

'BACK END > Deep Learning' 카테고리의 다른 글

[딥러닝] Neural Network  (0) 2021.03.19
[딥러닝] KNN  (0) 2021.03.18
[딥러닝] Decision Tree  (0) 2021.03.17
[딥러닝] 나이브 베이즈  (0) 2021.03.17
[딥러닝] PCA  (0) 2021.03.16

 

의사결정 나무(Decision Tree)

 : CART - classification과 Regression 모두 가능
 : 여러 규칙을 순차적으로 적용하면서 분류나 예측을 진행하는 단순 알고리즘 사용 모델

 

Random Forest

앙상블 모델

base 모델로 Decision Tree

 

 * tree1.py

import pydotplus
from sklearn import tree

# height, hair로 남녀 구분
x = [[180, 15],
     [177, 42],
     [156, 35],
     [174, 5],
     [166, 33]]

y = ['man', 'women', 'women', 'man', 'women']
label_names = ['height', 'hair Legnth']

model = tree.DecisionTreeClassifier(criterion='entropy', random_state=0)
print(model)
fit = model.fit(x, y)
print('acc :{:.3f}'.format(fit.score(x, y))) # acc :1.000

mydata = [[171, 8]]
pred =  fit.predict(mydata)
print('pred :', pred) # pred : ['man']

from sklearn import tree

tree.DecisionTreeClassifier() : 

scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html

 

sklearn.tree.DecisionTreeClassifier — scikit-learn 0.24.1 documentation

 

scikit-learn.org

# 시각화 - graphviz 툴을 사용
import collections

dot_data = tree.export_graphviz(model, feature_names=label_names, out_file=None,\
                                filled = True, rounded=True)
graph = pydotplus.graph_from_dot_data(dot_data)
colors = ('red', 'orange')
edges = collections.defaultdict(list) # list type 변수

for e in graph.get_edge_list():
    edges[e.get_source()].append(int(e.get_destination()))

for e in edges:
    edges[e].sort()
    for i in range(2):
        dest = graph.get_node(str(edges[e][i]))[0]
        dest.set_fillcolor(colors[i])

graph.write_png('tree.png') # 이미지 저장

import matplotlib.pyplot as plt

img = plt.imread('tree.png')
plt.imshow(img)
plt.show()

 


 * tree2_iris.py

...

# 의사결정 나무 모델
from sklearn.tree import DecisionTreeClassifier
model = DecisionTreeClassifier(criterion='entropy', max_depth=5)

...
...
# 트리의 특성 중요도 : 전체 트리 결정에 각 특성이 어느정도 중요한지 평가
print('특성 중요도 : \n{}'.format(model.feature_importances_))

def plot_feature_importances(model):
    n_features = x.shape[1] # 4
    plt.barh(range(n_features), model.feature_importances_, align='center')
    #plt.yticks(np.range(n_features), iris.featrue_names[2:4])
    plt.xlabel('특성중요도')
    plt.ylabel('특성')
    plt.ylim(-1, n_features)

plot_feature_importances(model)
plt.show()

# graphviz
from sklearn import tree
from io import StringIO
import pydotplus

dot_data = StringIO() # 파일 흉내를 내는 역할
tree.export_graphviz(model, out_file = dot_data,\
                     feature_names = iris.feature_names[2:4])
graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
graph.write_png('tree2.png')

import matplotlib.pyplot as plt

img = plt.imread('tree2.png')
plt.imshow(img)
plt.show()

 

'BACK END > Deep Learning' 카테고리의 다른 글

[딥러닝] KNN  (0) 2021.03.18
[딥러닝] RandomForest  (0) 2021.03.17
[딥러닝] 나이브 베이즈  (0) 2021.03.17
[딥러닝] PCA  (0) 2021.03.16
[딥러닝] SVM  (0) 2021.03.16

나이브 베이즈(Naive Bayes) 분류 모델

: feature가 주어졌을 때 label의 확률을 구함. P(L|Feature)

 

P(A|B) = P(B|A)P(A)/P(B)

P(A|B) : 사건B가 발생한 상태에서 사건A가 발생할 조건부 확률

P(label|feature)

 

 * bayes1.py

from sklearn.naive_bayes import GaussianNB
import numpy as np
from sklearn import metrics

x = np.array([1,2,3,4,5])
x = x[:, np.newaxis] # np.newaxis 차원 확대
print(x)
'''
[[1]
 [2]
 [3]
 [4]
 [5]]
'''
y = np.array([1,3,5,7,9])
print(y)

model = GaussianNB().fit(x, y)
pred = model.predict(x)
print(pred) # [1 3 5 7 9]
print('acc :', metrics.accuracy_score(y, pred)) # acc : 1.0

from sklearn.naive_bayes import GaussianNB

GaussianNB()

# new data
new_x = np.array([[0.5],[2.3], [12], [0.1]])
new_pred = model.predict(new_x)
print(new_pred) # [1 3 9 1]

 

 - One-hot encoding : 데이터를 0과 1로 변환(2진수)

: feature 데이터를 One-hot encoding

: 모델의 성능향상

x = '1,2,3,4,5'
x = x.split(',')
x = np.eye(len(x))
print(x)
'''
[[1. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0.]
 [0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 1.]]
'''
y = np.array([1,3,5,7,9])

model = GaussianNB().fit(x, y)
pred = model.predict(x)
print(pred) # [1 3 5 7 9]
print('acc :', metrics.accuracy_score(y, pred)) # acc : 1.0
from sklearn.preprocessing import OneHotEncoder
x = '1,2,3,4,5'
x = x.split(',')
x = np.array(x)
x = x[:, np.newaxis]
'''
[['1']
 ['2']
 ['3']
 ['4']
 ['5']]
'''

one_hot = OneHotEncoder(categories = 'auto')
x = one_hot.fit_transform(x).toarray()
print(x)
'''
[[1. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0.]
 [0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 1.]]
'''
y = np.array([1,3,5,7,9])

model = GaussianNB().fit(x, y)
pred = model.predict(x)
print(pred) # [1 3 5 7 9]
print('acc :', metrics.accuracy_score(y, pred)) # acc : 1.0

 

 * bayes3_text.py

# 나이브베이즈 분류모델로 텍스트 분류
from sklearn.datasets import fetch_20newsgroups

data = fetch_20newsgroups()
print(data.target_names)

categories = ['talk.religion.misc', 'soc.religion.christian',
              'sci.space', 'comp.graphics']

train = fetch_20newsgroups(subset='train', categories=categories)
test = fetch_20newsgroups(subset='test', categories=categories)
print(train.data[5])  # 데이터 중 대표항목

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import make_pipeline

# 각 문자열의 콘텐츠를 숫자벡터로 전환
model = make_pipeline(TfidfVectorizer(), MultinomialNB())  # 작업을 연속적으로 진행
model.fit(train.data, train.target)
labels = model.predict(test.data)

from sklearn.metrics import confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns

mat = confusion_matrix(test.target, labels)  # 오차행렬 보기
sns.heatmap(mat.T, square=True, annot=True, fmt='d', cbar=False,
            xticklabels=train.target_names, yticklabels=train.target_names)
plt.xlabel('true label')
plt.ylabel('predicted label')
plt.show()

# 하나의 문자열에 대해 예측한 범주 변환용 유틸 함수 작성
def predict_category(s, train=train, model=model):
    pred = model.predict([s])
    return train.target_names[pred[0]]

print(predict_category('sending a payload to the ISS'))
print(predict_category('discussing islam vs atheism'))
print(predict_category('determining the screen resolution'))

# 참고 도서 : 파이썬 데이터사이언스 핸드북 ( 출판사 : 위키북스)

 

 

'BACK END > Deep Learning' 카테고리의 다른 글

[딥러닝] RandomForest  (0) 2021.03.17
[딥러닝] Decision Tree  (0) 2021.03.17
[딥러닝] PCA  (0) 2021.03.16
[딥러닝] SVM  (0) 2021.03.16
[딥러닝] 로지스틱 회귀  (0) 2021.03.15

특성공학중 PCA(Principal Component Analysis)
 : 특성을 단순히 선택하는 것이 아니라 특성들의 조합으로 새로운 특성을 생성

 : PCA(주성분 분석)는 특성 추출(Feature Extraction) 기법에 속함

 

iris dataset으로 차원 축소 (4개의 열을 2(sepal, petal))

 * pca_test.py

from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from sklearn.datasets import load_iris
plt.rc('font', family='malgun gothic')

iris = load_iris()
n = 10
x = iris.data[:n, :2] # sepal 자료로 패턴확인
print('차원 축소 전  x:\n', x, x.shape, type(x)) # (10, 2) <class 'numpy.ndarray'>
'''
 [[5.1 3.5]
 [4.9 3. ]
 [4.7 3.2]
 [4.6 3.1]
 [5.  3.6]
 [5.4 3.9]
 [4.6 3.4]
 [5.  3.4]
 [4.4 2.9]
 [4.9 3.1]]
'''
print(x.T)
# [[5.1 4.9 4.7 4.6 5.  5.4 4.6 5.  4.4 4.9]
#  [3.5 3.  3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1]]

from sklearn.datasets import load_iris

load_iris() : ndarray type의 iris dataset load.

 

# 시각화
plt.plot(x.T, 'o:')
plt.xticks(range(2), labels=['꽃받침 길이', '꽃받침 폭'])
plt.xlim(-0.5, 2)
plt.ylim(2.5, 6)
plt.title('iris 특성')
plt.legend(['표본{}'.format(i + 1) for i in range(n)])
plt.show()

 

# 시각화2 : 산포도
plt.figure(figsize=(8, 8))
df = pd.DataFrame(x)
ax = sns.scatterplot(df[0], df[1], data=df , marker='s', s = 100, color=".2")
for i in range(n):
    ax.text(x[i, 0] - 0.05, x[i, 1] + 0.03, '표본{}'.format(i + 1))
    
plt.xlabel('꽃받침 길이')
plt.ylabel('꽃받침 폭')
plt.title('iris 특성')
plt.show()

# PCA
pca1 = PCA(n_components = 1)
x_row = pca1.fit_transform(x) # 1차원 근사데이터를 반환. 비 지도 학습
print('x_row :\n', x_row, x_row.shape) # (10, 1)
'''
[[ 0.30270263]
 [-0.1990931 ]
 [-0.18962889]
 [-0.33097106]
 [ 0.30743473]
 [ 0.79976625]
 [-0.11185966]
 [ 0.16136046]
 [-0.61365539]
 [-0.12605597]]
'''

x2 = pca1.inverse_transform(x_row)
print('복귀 후 값:\n', x2, x2.shape) # (10, 2)
'''
 [[5.06676112 3.53108532]
 [4.7240094  3.1645881 ]
 [4.73047393 3.17150049]
 [4.63393012 3.06826822]
 [5.06999338 3.53454152]
 [5.40628057 3.89412635]
 [4.78359423 3.22830091]
 [4.97021731 3.42785306]
 [4.44084251 2.86180369]
 [4.77389743 3.21793233]]
'''
print(x_row[0]) # [0.30270263]
print(x2[0, :]) # [5.06676112 3.53108532]
# 시각화2 : 산포도 - 사용
df = pd.DataFrame(x)
ax = sns.scatterplot(df[0], df[1], data=df , marker='s', s = 100, color=".2")
for i in range(n):
    d = 0.03 if x[i, 1] > x2[i, 1] else -0.04
    ax.text(x[i, 0] - 0.05, x[i, 1] + 0.03, '표본{}'.format(i + 1))
    plt.plot([x[i, 0], x2[i, 0]], [x[i, 1], x2[i, 1]], "k--")
plt.plot(x2[:, 0], x2[:, 1], "o-", markersize=10, color="b")
plt.plot(x[:, 0].mean(), x[:, 1].mean(), markersize=10, marker="D")
plt.axvline(x[:, 0].mean(), c='r') # 세로선
plt.axhline(x[:, 1].mean(), c='r') # 가로선
plt.xlabel('꽃받침 길이')
plt.ylabel('꽃받침 폭')
plt.title('iris 특성')
plt.show()

x = iris.data
pca2 = PCA(n_components = 2)
x_row2 = pca2.fit_transform(x)
print('x_row2 :\n', x_row2, x_row2.shape)

x4 = pca2.inverse_transform(x_row2)
print('최초자료 :', x[0])         # 최초자료 : [5.1 3.5 1.4 0.2]
print('차원축소 :', x_row2[0])    # 차원축소 : [-2.68412563  0.31939725]
print('최초복귀 :', x4[0, :])     # 최초복귀 : [5.08303897 3.51741393 1.40321372 0.21353169]

print()
iris2 = pd.DataFrame(x_row2, columns=['sepal', 'petal'])
iris1 = pd.DataFrame(x, columns=['sepal_Length', 'sepal_width', 'petal_Length', 'petal_width'])
print(iris2.head(3)) # 차원 축소
'''
      sepal     petal
0 -2.684126  0.319397
1 -2.714142 -0.177001
2 -2.888991 -0.144949
'''
print(iris1.head(3)) # 본래 데이터
'''
   sepal_Length  sepal_width  petal_Length  petal_width
0           5.1          3.5           1.4          0.2
1           4.9          3.0           1.4          0.2
2           4.7          3.2           1.3          0.2
'''

 

'BACK END > Deep Learning' 카테고리의 다른 글

[딥러닝] Decision Tree  (0) 2021.03.17
[딥러닝] 나이브 베이즈  (0) 2021.03.17
[딥러닝] SVM  (0) 2021.03.16
[딥러닝] 로지스틱 회귀  (0) 2021.03.15
[딥러닝] 다항회귀  (0) 2021.03.12

SVM(Support Vector Machine)

 : 두 데이터 사이에 구분을 위해 사용

 : 각 데이터의 중심을 기준으로 초평면(Optimal Hyper Plane) 구한다.

 : 초평면과 가까운 데이터를 support vector라 한다.

 : XOR 처리 가능

 

XOR 연산 처리(분류)

 * svm1.py

xor_data = [
    [0,0,0],
    [0,1,1],
    [1,0,1],
    [1,1,0],
]
#print(xor_data)

import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn import svm

xor_df = pd.DataFrame(xor_data)

feature = np.array(xor_df.iloc[:, 0:2])
label = np.array(xor_df.iloc[:, 2])
print(feature)
'''
[[0 0]
 [0 1]
 [1 0]
 [1 1]]
'''
print(label) # [0 1 1 0]
model = LogisticRegression() # 선형분류 모델
model.fit(feature, label)
pred = model.predict(feature)
print('pred :', pred)
# pred : [0 0 0 0]

model = svm.SVC()             # 선형, 비선형(kernel trick 사용) 분류모델
model.fit(feature, label)
pred = model.predict(feature)
print('pred :', pred)
# pred : [0 1 1 0]

# Sopport vector 확인해보기 
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
import numpy as np

plt.rc('font', family='malgun gothic')

X, y = make_blobs(n_samples=50, centers=2, cluster_std=0.5, random_state=4)
y = 2 * y - 1

plt.scatter(X[y == -1, 0], X[y == -1, 1], marker='o', label="-1 클래스")
plt.scatter(X[y == +1, 0], X[y == +1, 1], marker='x', label="+1 클래스")
plt.xlabel("x1")
plt.ylabel("x2")
plt.legend()
plt.title("학습용 데이터")
plt.show()

from sklearn.svm import SVC
model = SVC(kernel='linear', C=1.0).fit(X, y)  # tuning parameter  값을 변경해보자.

xmin = X[:, 0].min()
xmax = X[:, 0].max()
ymin = X[:, 1].min()
ymax = X[:, 1].max()
xx = np.linspace(xmin, xmax, 10)
yy = np.linspace(ymin, ymax, 10)
X1, X2 = np.meshgrid(xx, yy)

z = np.empty(X1.shape)
for (i, j), val in np.ndenumerate(X1):    # 배열 좌표와 값 쌍을 생성하는 반복기를 반환
    x1 = val
    x2 = X2[i, j]
    p = model.decision_function([[x1, x2]])
    z[i, j] = p[0]

levels = [-1, 0, 1]
linestyles = ['dashed', 'solid', 'dashed']
plt.scatter(X[y == -1, 0], X[y == -1, 1], marker='o', label="-1 클래스")
plt.scatter(X[y == +1, 0], X[y == +1, 1], marker='x', label="+1 클래스")
plt.contour(X1, X2, z, levels, colors='k', linestyles=linestyles)
plt.scatter(model.support_vectors_[:, 0], model.support_vectors_[:, 1], s=300, alpha=0.3)

x_new = [10, 2]
plt.scatter(x_new[0], x_new[1], marker='^', s=100)
plt.text(x_new[0] + 0.03, x_new[1] + 0.08, "테스트 데이터")

plt.xlabel("x1")
plt.ylabel("x2")
plt.legend()
plt.title("SVM 예측 결과")
plt.show()

# Support Vectors 값 출력
print(model.support_vectors_)
'''
[[9.03715314 1.71813465]
 [9.17124955 3.52485535]]
'''


 * svm2_iris.py

 

 


BMI의 계산방법을 이용하여 많은 양의 자료를 생성한 후 분류 모델로 처리

계산식    신체질량지수(BMI)=체중(kg)/[신장(m)]2
판정기준    저체중    20 미만
정상    20 - 24
과체중    25 - 29
비만    30 이상

 

 * svm3_bmi.py

print(67/((170 / 100) * (170 / 100)))

import random

def calc_bmi(h,w):
    bmi = w / (h / 100)**2
    if bmi < 18.5: return 'thin'
    if bmi < 23: return 'normal'
    return 'fat'
print(calc_bmi(170, 65))
fp = open('bmi.csv', 'w')
fp.write('height, weight, label\n')

cnt = {'thin':0, 'normal':0, 'fat':0}

for i in range(50000):
    h = random.randint(150, 200)
    w = random.randint(35, 100)
    label = calc_bmi(h, w)
    cnt[label] += 1
    fp.write('{0},{1},{2}\n'.format(h, w, label))
fp.close()
print('good')
# BMI dataset으로 분류
from sklearn import svm, metrics
from sklearn.model_selection import train_test_split
import pandas as pd
import matplotlib.pyplot as plt

tbl = pd.read_csv('bmi.csv')

# 칼럼을 정규화
label = tbl['label']
print(label)
w = tbl['weight'] / 100
h = tbl['height'] / 200
wh = pd.concat([w, h], axis=1)
print(wh.head(5), wh.shape)
'''
   weight  height
0    0.69   0.850
1    0.51   0.835
2    0.70   0.830
3    0.71   0.945
4    0.50   0.980 (50000, 2)
'''
label = label.map({'thin':0, 'normal':1, 'fat':2})
'''
0    2
1    0
2    2
3    1
4    0
'''
print(label[:5], label.shape) # (50000,)
# train/test
data_train, data_test, label_train, label_test = train_test_split(wh, label)
print(data_train.shape, data_test.shape) # (37500, 2) (12500, 2)

# model
model = svm.SVC(C=0.01).fit(data_train, label_train)
#model = svm.LinearSVC().fit(data_train, label_train)
print(model)
# 학습한 데이터의 결과가 신뢰성이 있는지 확인하기 위해 교차검증 p221
from sklearn import model_selection
cross_vali = model_selection.cross_val_score(model, wh, label, cv=3)
# k ford classification
# train 7, test 3 => train으로 3등분 하여 재검증
# 검증 학습 학습
# 학습 검증 학습
# 학습 학습 검증
print('각각의 검증 결과:', cross_vali)          # [0.96754065 0.96400072 0.96783871]
print('평균 검증 결과:', cross_vali.mean())    # 0.9664600275737195
pred = model.predict(data_test)
ac_score = metrics.accuracy_score(label_test, pred)
print('분류 정확도 :', ac_score) # 분류 정확도 : 0.96816
print(metrics.classification_report(label_test, pred))
'''
              precision    recall  f1-score   support

           0       0.98      0.97      0.98      4263
           1       0.91      0.94      0.93      2644
           2       0.98      0.98      0.98      5593

    accuracy                           0.97     12500
   macro avg       0.96      0.96      0.96     12500
weighted avg       0.97      0.97      0.97     12500
'''
# 시각화
tbl2 = pd.read_csv('bmi.csv', index_col = 2)
print(tbl2[:3])
'''
       height  weight
label                
fat       170      69
thin      167      51
fat       166      70
'''

def scatter_func(lbl, color):
    b = tbl2.loc[lbl]
    plt.scatter(b['weight'], b['height'], c=color, label=lbl)


fig = plt.figure()
scatter_func('fat', 'red')
scatter_func('normal', 'yellow')
scatter_func('thin', 'blue')
plt.legend()
plt.savefig('bmi_test.png')
plt.show()


SVM 모델로 이미지 분류

 * svm4.py

a

from sklearn.datasets import fetch_lfw_people

fetch_lfw_people(min_faces_per_person = 60) : 인물 사진 data load. min_faces_per_person : 최초 

 

 

scikit-learn.org/stable/modules/generated/sklearn.datasets.fetch_lfw_people.html

 

sklearn.datasets.fetch_lfw_people — scikit-learn 0.24.1 documentation

 

scikit-learn.org

import matplotlib.pyplot as plt
from sklearn.metrics._classification import classification_report

faces = fetch_lfw_people(min_faces_per_person = 60) 
print(faces)

print(faces.DESCR)
print(faces.data)
print(faces.data.shape) # (729, 2914)
print(faces.target)
print(faces.target_names)
print(faces.images.shape) # (729, 62, 47)

print(faces.images[0])
print(faces.target_names[faces.target[0]])
plt.imshow(faces.images[0], cmap='bone') # cmap : 색
plt.show()

fig, ax = plt.subplots(3, 5)
print(fig)          # Figure(640x480)
print(ax.flat)      # <numpy.flatiter object at 0x00000235198C5D30>
print(len(ax.flat)) # 15
for i, axi in enumerate(ax.flat):
    axi.imshow(faces.images[i], cmap='bone')
    axi.set(xticks=[], yticks=[], xlabel=faces.target_names[faces.target[i]])
plt.show()

 - 주성분 분석으로 이미지 차원을 축소시켜 분류작업을 진행

from sklearn.svm import SVC
from sklearn.decomposition import PCA
from sklearn.pipeline import make_pipeline

m_pca = PCA(n_components=150, whiten=True, random_state = 0)
m_svc = SVC(C=1)
model = make_pipeline(m_pca, m_svc)
print(model)
# Pipeline(steps=[('pca', PCA(n_components=150, random_state=0, whiten=True)),
#                 ('svc', SVC(C=1))])

 - train/test

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(faces.data, faces.target, random_state=1)
print(x_train[0], x_train.shape) # (546, 2914)
print(y_train[0], y_train.shape) # (546,)

model.fit(x_train, y_train)  # train data로 모델 fitting
pred = model.predict(x_test)
print('pred :', pred)   # pred : [1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 ..
print('read :', y_test) # read : [0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 ..

 - 분류 정확도

from sklearn.metrics import classification_report

print(classification_report(y_test, pred, target_names = faces.target_names)) # 분류 정확도
'''
                   precision    recall  f1-score   support

  Donald Rumsfeld       1.00      0.25      0.40        20
    George W Bush       0.80      1.00      0.89       132
Gerhard Schroeder       1.00      0.45      0.62        31

         accuracy                           0.83       183
        macro avg       0.93      0.57      0.64       183
     weighted avg       0.86      0.83      0.79       183
=> f1-score/accuracy -> 0.83
'''

from sklearn.metrics import confusion_matrix, accuracy_score

mat = confusion_matrix(y_test, pred)
print('confusion_matrix :\n', mat)
'''
 [[  5  15   0]
 [  0 132   0]
 [  0  17  14]]
 '''
print('acc :', accuracy_score(y_test, pred)) # 0.82513

 - 분류결과를 시각화

# x_test[0] 하나 미리보기.
plt.subplots(1, 1)
print(x_test[0], ' ', x_test[0].shape)
# [ 24.333334  33.        72.666664 ... 201.66667  201.33333  155.33333 ]   (2914,)
print(x_test[0].reshape(62, 47)) # 1차원을 2차원으로 변환해야 이미지 출력 가능
plt.imshow(x_test[0].reshape(62, 47), cmap='bone')
plt.show()

fig, ax = plt.subplots(4, 6)
for i, axi in enumerate(ax.flat):
    axi.imshow(x_test[i].reshape(62, 47), cmap='bone')
    axi.set(xticks=[], yticks=[])
    axi.set_ylabel(faces.target_names[pred[i]].split()[-1], color='black' if pred[i] == y_test[i] else 'red')
    fig.suptitle('pred result', size = 14)
plt.show()

 - 5차 행렬 시각화

import seaborn as sns
sns.heatmap(mat.T, square = True, annot=True, fmt='d', cbar=False, \
            xticklabels=faces.target_names, yticklabels=faces.target_names)
plt.xlabel('true(read) label')
plt.ylabel('predicted label')
plt.show()

 

 

'BACK END > Deep Learning' 카테고리의 다른 글

[딥러닝] 나이브 베이즈  (0) 2021.03.17
[딥러닝] PCA  (0) 2021.03.16
[딥러닝] 로지스틱 회귀  (0) 2021.03.15
[딥러닝] 다항회귀  (0) 2021.03.12
[딥러닝] 단순선형 회귀, 다중선형 회귀  (0) 2021.03.11

회귀분석 Regression

 : 각각의 데이터에 대한 잔차 제곱합이 최소가 되는 추세선을 만들고, 이를 통해 독립 변수가 종속변수에 얼마나 영향을 주는지 인과관계를 분석.

 : 독립변수 - 연속형, 종속변수 - 연속형.

 : 두 변수는 상관관계 및 인과관계가 있어야한다. (상관계수 > 0.3)

 : 정량적인 모델 생성.

 

 - 기계 학습(지도학습) : 학습을 통해 모델 생성 후, 새로운 데이터에 대한 예측 및 분류

선형회귀 Linear Regression

최소 제곱법(Least Square Method)


Y = a + b * X

 

 

선형회귀분석의 기존 가정 충족 조건

  • 선형성 : 독립변수(feature)의 변화에 따라 종속변수도 일정 크기로 변화해야 한다.
  • 정규성 : 잔차항이 정규분포를 따라야 한다.
  • 독립성 : 독립변수의 값이 서로 관련되지 않아야 한다.
  • 등분산성 : 그룹간의 분산이 유사해야 한다. 독립변수의 모든 값에 대한 오차들의 분산은 일정해야 한다.
  • 다중공선성 : 다중회귀 분석 시 3 개 이상의 독립변수 간에 강한 상관관계가 있어서는 안된다.

 

 - 최소 제곱해를 선형 행렬 방정식으로 얻기

 

 * linear_reg1.py

import numpy.linalg as lin
import numpy as np
import matplotlib.pyplot as plt

x = np.array([0, 1, 2, 3])
y = np.array([-1, 0.2, 0.9, 2.1])

plt.plot(x, y)
plt.grid(True)
plt.show()

 

 

A = np.vstack([x, np.ones(len(x))]).T
print(A)
'''
[[0. 1.]
 [1. 1.]
 [2. 1.]
 [3. 1.]]
'''

# y = mx + c
m, c = np.linalg.lstsq(A, y, rcond=None)[0]
print('기울기 :', m, ' y절편:', c) # 기울기 : 0.9999999999999997   y절편 : -0.949999999999999

plt.plot(x, y, 'o', label='Original data', markersize=10)
plt.plot(x, m*x + c, 'r', label='Fitted line')
plt.legend()
plt.show()

np.vstack(x, y) : x에 y 행 추가

np.ones(x) : x X x의 1로 채워진 행렬 생성

x.T : 행열 변경

import numpy.linalg as lin

lin.lstsq() : 최소제곱법

# yhat = 0.9999999999999997 * x -0.949999999999999
print(0.9999999999999997 * 1 -0.949999999999999) # 0.05000000000000071
print(0.9999999999999997 * 3 -0.949999999999999) # 2.0500000000000003
print(0.9999999999999997 * 123 -0.949999999999999) # 122.04999999999995

 

 

모델 생성

 * linear_reg2.py

 

방법 1 : make_regression을 사용, model X

import statsmodels.api as sm
from sklearn.datasets import make_regression
import numpy as np

np.random.seed(12)
x, y, coef = make_regression(n_samples=50, n_features=1, bias=100, coef=True)
print('x :{}, y:{}, coef:{}'.format(x, y, coef))
'''
x :[[-1.70073563]
 [-0.67794537]
 y:[ -52.17214291   39.34130801  

  '''
# 기울기 coef:89.47430739278907
# 회귀식 y = a + bx      y = 100 + 89.47430739278907 * x
y_pred = 100 + 89.47430739278907  * -1.70073563
print('y_pred :', y_pred) # y_pred : -52.17214255248879

xx = x
yy = y

 

방법 2 : Linear Regression을 사용. model O

from sklearn.linear_model import LinearRegression
model = LinearRegression()
fit_model = model.fit(xx, yy) # 학습 데이터로 모형 추정 : y절편, 기울기 get.
print(fit_model.coef_)      # 기울기 89.47430739
print(fit_model.intercept_) # y절편 100.0

# 예측값 확인 함수
y_pred2 = fit_model.predict(xx[[0]])
print('y_pred2 :', y_pred2)

y_pred2_new = fit_model.predict([[66]])
print('y_pred2_new :', y_pred2_new)

 

방법 3 : ols 사용. model O.

import statsmodels.formula.api as smf
import pandas as pd

x1 = xx.flatten() # 차원 축소
print(x1.shape)
y1 = yy
print(y1)

data = np.array([x1, y1])
df = pd.DataFrame(data.T)
df.columns = ['x1', 'y1']
print(df.head(3))
'''
         x1          y1
0 -1.700736  -52.172143
1 -0.677945   39.341308
2  0.318665  128.512356
'''

model2 = smf.ols(formula='y1 ~ x1', data=df).fit()
print(model2.summary())

# 예측값 확인 함수
print(x1[:2]) # [-1.70073563 -0.67794537]
new_df = pd.DataFrame({'x1':[-1.70073563, -0.67794537]}) # 기존 자료로 검증
new_pred = model2.predict(new_df)
print('new_pred :\n', new_pred)
'''
new_pred :
 0   -52.172143
1    39.341308
'''

new2_df = pd.DataFrame({'x1':[123, -2.34567]}) # 새로운 값에 대한 예측 결과 확인
new2_pred = model2.predict(new2_df)
print('new2_pred :\n', new2_pred)
'''
new2_pred :
 0    11105.339809
1     -109.877199
'''

 

 

방법 4 : linregress  사용. model O

 * liner_reg3.py

from scipy import stats
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

score_iq = pd.read_csv('../testdata/score_iq.csv')
print(score_iq.head(3))
'''
     sid  score   iq  academy  game  tv
0  10001     90  140        2     1   0
1  10002     75  125        1     3   3
2  10003     77  120        1     0   4
'''
print(score_iq.info())

# iq가 score에 영향을 주는 지 검정
# iq로 score(시험점수) 값 예측 - 정량적 분석

x = score_iq.iq
y = score_iq.score

 

# 상관계수
print(np.corrcoef(x, y)) # numpy  0.88222034
print(score_iq.corr())   # pandas 0.882220

 

# 두 변수는 인과 관계가 있다고 보고, 선형회귀 분석 진행.
model = stats.linregress(x, y)
print(model)
print('p-value :', model.pvalue)  # p-value : 2.8476895206683644e-50
print('기울기 :', model.slope)      # 기울기 : 0.6514309527270075
print('y절편 :', model.intercept)  # y절편 : -2.8564471221974657
# pvalue=2.8476895206683644e-50 < 0.05 이므로 현재 모델은 유의하다.
# iq가 score에 영향을 준다.
# y = 0.6514309527270075 * x -2.8564471221974657 
print('예측결과 :', 0.6514309527270075 * 140 -2.8564471221974657)
# 예측결과 : 88.34388625958358
print('예측결과 :', 0.6514309527270075 * 125 -2.8564471221974657)
# 예측결과 : 78.57242196867847
print('예측결과 :', 0.6514309527270075 * 80 -2.8564471221974657)
# 예측결과 : 49.25802909596313
print('예측결과 :', 0.6514309527270075 * 155 -2.8564471221974657)
# 예측결과 : 98.11535055048869
print('예측결과 :', model.slope * 155 + model.intercept)
# 예측결과 : 98.11535055048869
# linregress는 predict()가 지원되지않음. numpy의 polyval 이용.
#print('예측결과 :', np.polyval([model.slope, model.intercept], np.array(score_iq['iq'])))
new_df = pd.DataFrame({'iq':[55, 66, 77, 88, 155]})
print('예측결과 :\n', np.polyval([model.slope, model.intercept], new_df))
'''
예측결과 :
 [[32.97225528]
 [40.13799576]
 [47.30373624]
 [54.46947672]
 [98.11535055]]
'''

np.polyval([기울기, y절편], data) : numpy predict함수

 

 

'BACK END > Deep Learning' 카테고리의 다른 글

[딥러닝] 다항회귀  (0) 2021.03.12
[딥러닝] 단순선형 회귀, 다중선형 회귀  (0) 2021.03.11
[딥러닝] 공분산, 상관계수  (0) 2021.03.10
[딥러닝] 이항검정  (0) 2021.03.10
[딥러닝] ANOVA  (0) 2021.03.08

 

Python 정리 (내용을 클릭하세요)
1. 변수 2. 연산자 3. 집합형 자료 4. 정규 표현식 5. 조건 판단문 if
6. 반복문 while 7. 반복문 for 8. 함수 9. 변수의 생존 범위 10. closure(클로저)
11. 일급함수 12. Module 13. 사용자 정의 모듈 14. turtle 15. 외부 모듈 사용
16. Class 17. 포함관계 (has a) 18. 상속 19. 메소드 오버라이딩 20. 다중 상속
21. 추상클래스 22. 예외처리 23. file i/o 24. wxPython 25. SQLite
26.  DB 연동 27. socket 28. Thread 29. multi thread chat 30. pool
31. process 32. 웹 크롤링(crawling) 33. HttpServer 34. CGI 35. 챗봇(chatbot)

 

20. 다중 상속

21. 추상클래스

22. 예외처리

23. file i/o

24. wxPython

25. SQLite

26. 원격 DB 연동

27. socket

28. Thread

29. 멀티 쓰레드 채팅 프로그램

30. pool

31. process

32. 웹 크롤링

33. HttpServer

34. CGI

35. 챗봇(chatbot)


20. 다중 상속 - 순서 중요

 * test_24

print("이전 작업 진행")
class Tiger:
    data = '호랑이 세상'
    
    def cry(self):
        print('호랑이 울음')
    def eat(self):
        print('고기 먹음')

class Lion:
    data = '사자 세상'
    
    def cry(self):
        print('사자 울음')
        
    def hobby(self):
        print('사자 낮잠')

class Liger(Tiger, Lion): # 먼저 명시한 부모를 먼저 인식
    pass

aa = Liger()
aa.cry()        # 호랑이 울음
aa.eat()        # 고기 먹음
aa.hobby()      # 사자 낮잠
print(aa.data)  # 호랑이 세상
print()

class Liger2(Lion, Tiger):
    data = 'Liger2 멤버 변수'
    
    def play(self):
        print("Liger2 고유 메소드")
        self.hobby()
        super().hobby()
        print(self.data)
        print(super().data)
bb = Liger2()
bb.cry()       # 사자 울음
bb.eat()       # 고기 먹음
bb.hobby()     # 사자 낮잠
print(bb.data) # Liger2 멤버 변수
bb.play()
# Liger2 고유 메소드
# 사자 낮잠
# 사자 낮잠
# Liger2 멤버 변수
# 사자 세상
class Animal:
    def move(self):
        pass
    
class Dog(Animal):
    name = '개'
    
    def move(self):
        print('개가 낮에 돌아다님')
    
class Cat(Animal):
    name = '고양이'
    
    def move(self):
        print('고양이가 밤에 돌아다님')
    
class Wolf(Dog, Cat):
    pass

class Fox(Cat, Dog):
    def move(self):
        print('여우가 돌아다님(오버라이딩)')
    
    def foxMove(self):
        print('여우 고유 메소드')
dog = Dog()
cat = Cat()
wolf = Wolf()
fox = Fox()

anis = [dog, cat, wolf, fox]
for a in anis:
    a.move()
# 개가 낮에 돌아다님
# 고양이가 밤에 돌아다님
# 개가 낮에 돌아다님
# 여우가 돌아다님(오버라이딩)

21. 추상클래스

추상클래스 : 추상 메소드를 가지는 클래스.
추상 메소드: 자식 클래스에서 부모의 추상메소드를 일반 메소드로 반드시 오버라이딩 하도록 강요.

 * test25_abstract

from abc import *

class TestClass(metaclass = ABCMeta): # 추상 클래스
    @abstractmethod
    def abcMethod(self):              # 추상 메소드
        pass
    
    def normalMethod(self):           # 일반 메소드
        print('일반 메소드')

tt = TestClass()   # TypeError: Can't instantiate abstract class TestClass with abstract methods abcMethod 
                   # 추상클래스가 추상메소드를 가질 경우 인스턴스 생성 시 error 발생.
                   # 추상클래스가 추상메소드를 가지지 않을 경우 인스턴스 생성 가능.
class Child1(TestClass): # 추상 클래스를 상속 받을 경우 추상메소드를 오버라이드 하지않을 경우 error 발생
    name = 'Child1'
    
    def abcMethod(self):
        print('Child1 추상 메소드를 오버라이딩하여 일반 메소드 생성')

# TypeError: Can't instantiate abstract class Child1 with abstract methods abcMethod
c1 = Child1()
c1.abcMethod()       # Child1 추상 메소드를 오버라이딩하여 일반 메소드 생성
c1.normalMethod()    # 일반 메소드
class Child2(TestClass):
    name = 'Child2'
    
    def abcMethod(self):
        print('Child2 추상 메소드를 오버라이딩하여 일반 메소드 생성')
        print('다른 클래스의 abcMethod와 이름은 같으나 다른 기능을 수행.')
        
    def normalMethod(self):
        print('부모의 normalMethod를 오버라이딩. 부모 메소드와 다른 역할 수행을 위해.')

c2 = Child2()
c2.abcMethod()      # Child2 추상 메소드를 오버라이딩하여 일반 메소드 생성
                    # 다른 클래스의 abcMethod와 이름은 같으나 다른 기능을 수행.
c2.normalMethod()   # 부모의 normalMethod를 오버라이딩. 부모 메소드와 다른 역할 수행을 위해.
print()

다형성 구현

my = c1
my.abcMethod()      # 1
                    #Child1 추상 메소드를 오버라이딩하여 일반 메소드 생성
my = c2
my.abcMethod()      # 1과 동일한 명령문이나 기능은 다름.
                    #Child2 추상 메소드를 오버라이딩하여 일반 메소드 생성
                    #다른 클래스의 abcMethod와 이름은 같으나 다른 기능을 수행.

클래스 연습문제 24-4

class Employee(metaclass= ABCMeta):
    def __init__(self, irum, nai):
        self.irum = irum
        self.nai = nai
    
    @abstractmethod
    def pay(self):
        pass
    
    @abstractmethod
    def data_print(self):
        pass
    
    def irumnai_print(self):
        print('이름 : ' + self.irum + ', 나이 : '+ str(self.nai), end = ', ')                     
                    
class Temporary(Employee):
    def __init__(self, irum, nai, ilsu, ildang):
        Employee.__init__(self, irum, nai)
        self.ilsu = ilsu
        self.ildang = ildang
        
    def pay(self):
        return self.ilsu * self.ildang; 
    
    def data_print(self):
        self.irumnai_print()
        print('월급 : ' + str(self.pay()))

t = Temporary('홍길도', 25, 20, 15000)
t.data_print() # 이름 : 홍길도, 나이 : 25, 월급 : 300000
class Regular(Employee):
    def __init__(self, irum, nai, salary):
        Employee.__init__(self, irum, nai)
        self.salary = salary
    
    def pay(self): # 추상 메소드 오버라이딩
        return self.salary; 
    
    def data_print(self):
        self.irumnai_print()
        print('급여 : ' + str(self.pay()))

r = Regular('한국인', 27, 3500000) # 이름 : 한국인, 나이 : 27, 급여 : 3500000
r.data_print()
class Salseman(Regular):
    def __init__(self, irum, nai, salary, sales, commission):
        Regular.__init__(self, irum, nai, salary)
        self.sales = sales
        self.commission = commission
    
    def pay(self): # 일반 메소드 오버라이딩
        return super().pay() + self.sales * self.commission; 
    
    def data_print(self):
        self.irumnai_print()
        print('수령액 : ' + str(self.pay()))
        
s = Salseman('손오공', 29, 1200000, 5000000, 0.25)
s.data_print() # 이름 : 손오공, 나이 : 29, 수령액 : 2450000.0

22. 예외처리

 * test26_try

try ~ except - 예상치 않은 에러에 대응하기 위한 문법

def divide(a, b):
    return a / b

c = divide(5, 2)
#c = divide(5, 0) # ZeroDivisionError: division by zero
print(c)
print()

try:
    c = divide(5, 2)
    #c = divide(5, 0)
    print(c)
    
    aa = [1, 2]
    print(aa[0])
    print(aa[1])
    #print(aa[2]) # IndexError: list index out of range
    
    f = open('c:/abc.txt') # FileNotFoundError: [Errno 2] No such file or directory: 'c:/abc.txt'
    
except ZeroDivisionError:
    print('두번째 인자에 0을 주지마세요')

except IndexError as e:
    print('Index Error : ', e)
except Exception as err:
    print("error 발생 : ", err)
finally:
    print('에러 유무에 관계없이 반드시 수행됨')

print('프로그램 종료')

 


23. file i/o

import os
print(os.getcwd())

try:
    print('파일 읽기')
    f1 = open(r'ftest.txt', mode ='r', encoding ='utf-8')
    print(f1) # <_io.TextIOWrapper name='ftest.txt' mode='r' encoding='utf-8'>
    print(f1.read())
    f1.close() # 파일 처리 종료시 close() : 사용했던 자원을 해제
    
    print('파일로 저장')
    f2 = open('ftest2.txt', mode = 'w', encoding = 'utf-8')
    f2.write('내 친구들\n')
    f2.write('홍길동 고길동\n')
    f2.close()
    print('저장 성공')
    
    print('파일에 내용추가')
    f2 = open('ftest2.txt', mode = 'a', encoding = 'utf-8')
    f2.write('손오공\n')
    f2.write('조조\n')
    f2.close()
    print('추가 성공')
    
    print('파일 읽기')
    f3 = open(r'ftest2.txt', mode ='r', encoding ='utf-8')
    print(f3.read()) # 전체 행 읽기
    #print(f3.readline()) # 한 행씩 읽기
    f3.close()
    
except Exception as e:
    print('에러 : ', e)

 - with문 사용 - close() 자동 수행

try:
    # 저장
    with open('ftest3.txt', mode = 'w', encoding = 'utf-8') as ff1:
        ff1.write('파이썬 문서 저장\n')
        ff1.write('내용\n')
        ff1.write('with문 사용으로 close() 하지않음\n')
    # 읽기
    with open('ftest3.txt', mode = 'r', encoding = 'utf-8') as ff2:
        print(ff2.read())
except Exception as e2:
    print('에러 발생', e2)

 - 피클링  : 복합 개체 처리(i/o)

import pickle

try:
    dicData = {'tom':'111-1111', 'james':'222-2222'}
    listData = ['마우스', '키보드']
    tupleData = (dicData, listData) # 복합객체
    
    with open('hi.dat', 'wb') as fobj:
        pickle.dump(tupleData, fobj)
        pickle.dump(listData, fobj)
    print('객체를 파일로 저장하기 성공')
    print('객체 읽기')
    with open('hi.dat', 'rb') as fobj2:
        a, b = pickle.load(fobj2)
        print(a) # {'tom': '111-1111', 'james': '222-2222'}
        print(b) # ['마우스', '키보드']
        c = pickle.load(fobj2)
        print(c)
except Exception as e3:
    print('error : ' + e3)

 * test28_file

 - 동 이름으로 우편번호와 주소 출력

try:
    dong = input('동이름 입력 : ')
    print(dong)
    with open(r'zipcode.txt', mode = 'r', encoding = 'euc-kr') as f:
        #print(f.read())
        line = f.readline()
        while line:
            lines = line.split('\t') # tab으로 구분
            #print(lines)
            if lines[3].startswith(dong): # 입력된 동 이름으로 시작되는 주소만 처리
                print('[' + lines[0] + '] '+ lines[1] + ' '+ lines[2] + \
                      ' '+ lines[3] + ' '+ lines[4])
            line = f.readline() # readline이 없을 때 까지 수행
            
except Exception as e:
    print('err',e)

 


24. wxPython

 - 설치

1 사이트 접속

wxpython.org/Phoenix/snapshot-builds/

 

Index of /Phoenix/snapshot-builds

 

wxpython.org

2 " wxPython-4.1.2a1.dev5103+4ab028d7-cp38-cp38-win_amd64.whl " 다운로드

 

3 anaconda prompt 실행

" cd C:\Users\wonh\Downloads\ " 입력(다운로드 파일 경로)

" dir wx* " 입력 후 하기 파일명 복사

" pip install wxPython-4.1.2a1.dev5103+4ab028d7-cp38-cp38-win_amd64.whl "입력

 

 * test29_gui1

# GUI (윈도우 프로그래밍)
# wxPython

import wx
# app = wx.App(False)
# frame = wx.Frame(None, wx.ID_ANY, 'Hi')
# frame.Show(True)
# app.MainLoop()

class Ex(wx.Frame):
    def __init__(self, parent, title):
        super(Ex, self).__init__(parent, title = title, size =(300, 300))
        
        # textBox 추가
        #self.txtA = wx.TextCtrl(self)
        #self.txtA = wx.TextCtrl(self, style = wx.TE_MULTILINE)
        
        # Label, textBox 사용
        panel = wx.Panel(self)
        wx.StaticText(panel, label = 'i d : ', pos = (5, 5))
        wx.StaticText(panel, label = 'pwd : ', pos = (5, 40))
        self.txtId = wx.TextCtrl(panel, pos = (40, 5))
        self.txtPwd = wx.TextCtrl(panel, pos = (40, 40), size = (200, -1))
        
        # Button : 디자인
        btn1 = wx.Button(panel, label = '버튼1', pos = (5,100))
        btn2 = wx.Button(panel, label = '버튼2', pos = (100,100))
        btn3 = wx.Button(panel, label = '종료', pos = (200,100))
        
        # Button에  대한 이벤트 처리 작업1
#         btn1.Bind(wx.EVT_BUTTON, self.btn1Method)
#         btn2.Bind(wx.EVT_BUTTON, self.btn2Method)
#         btn3.Bind(wx.EVT_BUTTON, self.btn3Method)
        
        # Button에  대한 이벤트 처리 작업2
        btn1.id = 1 # 각 버튼의 구분을 위해 id를 준다
        btn2.id = 2
        btn3.id = 3
        btn1.Bind(wx.EVT_BUTTON, self.OnClickMethod)
        btn2.Bind(wx.EVT_BUTTON, self.OnClickMethod)
        btn3.Bind(wx.EVT_BUTTON, self.OnClickMethod)
        
        self.Center()
        self.Show()
    
    def abc(self):
        print('일반 메소드')
    
    def btn1Method(self, event): # 이벤트 처리 메소드. event handler
        #print('버튼 1을 누르셨습니다')
        temp = self.txtId.GetValue()
        self.txtPwd.SetLabelText(temp)
    
    def btn2Method(self, event): # 이벤트 처리 메소드. event handler
        #print('버튼 2를 누르셨습니다')
        msgDial = wx.MessageDialog(self, '메세지', '제목', wx.OK)
        msgDial.ShowModal()
        msgDial.Destroy()
        
    def btn3Method(self, event): # 이벤트 처리 메소드. event handler
        #print('종료')
        self.Close() # wx.App()를 종료
        
    def OnClickMethod(self, event):
        #print(event.GetEventObject().id)
        #print('aa')
        if event.GetEventObject().id == 1:
            self.txtId.SetLabelText('id');
        elif event.GetEventObject().id == 2:
            self.txtPwd.SetLabelText('password');
        else:
            self.Close() 
        
if __name__ == '__main__':
    app = wx.App()
    Ex(None, title = '연습')
    app.MainLoop()

 * test30_gui2

# 레이아웃 관리자 클래스 중 Boxsizer 연습
import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        super(MyFrame, self).__init__(parent, title=title, size =(300, 350))
        
        panel1 = wx.Panel(self, -1, style = wx.SUNKEN_BORDER)
        panel2 = wx.Panel(self, -1, style = wx.SUNKEN_BORDER)
        
        panel1.SetBackgroundColour("Blue")
        panel2.SetBackgroundColour("red")
        
        box = wx.BoxSizer(wx.HORIZONTAL) # VERTICAL 
        box.Add(panel1, 1, wx.EXPAND)
        box.Add(panel2, 2, wx.EXPAND)
        
        self.SetSizer(box)
        self.Center()
        self.Show()

if __name__ == '__main__':
    app = wx.App()
    MyFrame(None, title = '레이아웃')
    app.MainLoop()

 

 - wxformbuilder - UI 편집 도구

 * test31_gui3

sourceforge.net/projects/wxformbuilder/

 

wxFormBuilder

Download wxFormBuilder for free. ALL DEVELOPMENT MOVED TO GITHUB https://github.com/wxFormBuilder/wxFormBuilder wxFormBuilder - a RAD tool for wxWidgets GUI design.

sourceforge.net

import wx
import wx.xrc

class MyFrame1 ( wx.Frame ):
    
    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"연습", pos = wx.DefaultPosition, size = wx.Size( 288,154 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
        
        #self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
        self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_MENU ) )
        
        bSizer1 = wx.BoxSizer( wx.VERTICAL )
        
        self.m_panel1 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer2 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_staticText1 = wx.StaticText( self.m_panel1, wx.ID_ANY, u"이름 : ", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText1.Wrap( -1 )
        bSizer2.Add( self.m_staticText1, 0, wx.ALL, 5 )
        
        self.txtName = wx.TextCtrl( self.m_panel1, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer2.Add( self.txtName, 0, wx.ALL, 5 )
        
        
        self.m_panel1.SetSizer( bSizer2 )
        self.m_panel1.Layout()
        bSizer2.Fit( self.m_panel1 )
        bSizer1.Add( self.m_panel1, 0, wx.ALL|wx.EXPAND, 5 )
        
        self.m_panel2 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer3 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_staticText2 = wx.StaticText( self.m_panel2, wx.ID_ANY, u"나이 : ", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText2.Wrap( -1 )
        bSizer3.Add( self.m_staticText2, 0, wx.ALL, 5 )
        
        self.txtAge = wx.TextCtrl( self.m_panel2, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer3.Add( self.txtAge, 0, wx.ALL, 5 )
        
        self.btnOk = wx.Button( self.m_panel2, wx.ID_ANY, u"확인", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer3.Add( self.btnOk, 0, wx.ALL, 5 )
        
        
        self.m_panel2.SetSizer( bSizer3 )
        self.m_panel2.Layout()
        bSizer3.Fit( self.m_panel2 )
        bSizer1.Add( self.m_panel2, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel3 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer4 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_staticText3 = wx.StaticText( self.m_panel3, wx.ID_ANY, u"결과 : ", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText3.Wrap( -1 )
        bSizer4.Add( self.m_staticText3, 0, wx.ALL, 5 )
        
        self.staShow = wx.StaticText( self.m_panel3, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        self.staShow.Wrap( -1 )
        bSizer4.Add( self.staShow, 0, wx.ALL, 5 )
        
        
        self.m_panel3.SetSizer( bSizer4 )
        self.m_panel3.Layout()
        bSizer4.Fit( self.m_panel3 )
        bSizer1.Add( self.m_panel3, 0, wx.EXPAND |wx.ALL, 5 )
        
        
        self.SetSizer( bSizer1 )
        self.Layout()
        
        self.Centre( wx.BOTH )
        
        # Connect Events
        self.btnOk.Bind( wx.EVT_BUTTON, self.OnClickMethod )
    
    def __del__( self ):
        pass
    
    
    # Virtual event handlers, overide them in your derived class
    def OnClickMethod( self, event ):
        #event.Skip()
        name = self.txtName.GetValue()
        if name == "":
            wx.MessageBox('이름 입력', '알림', wx.OK)
            return
        age = self.txtAge.GetValue()
        
        self.staShow.SetLabelText(name+" " + age)
    
if __name__ == '__main__':
    app = wx.App()
    MyFrame1(None).Show()
    app.MainLoop()
    

 

 * test32_gui_calc

import wx
import wx.xrc

class MyFrame1 ( wx.Frame ):
    
    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 308,303 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
        
        #self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
        self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_MENU ) )
        
        bSizer1 = wx.BoxSizer( wx.VERTICAL )
        
        self.m_panel1 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer2 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_staticText1 = wx.StaticText( self.m_panel1, wx.ID_ANY, u"숫자1", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText1.Wrap( -1 )
        bSizer2.Add( self.m_staticText1, 0, wx.ALL, 5 )
        
        self.txtNum1 = wx.TextCtrl( self.m_panel1, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer2.Add( self.txtNum1, 0, wx.ALL, 5 )
        
        
        self.m_panel1.SetSizer( bSizer2 )
        self.m_panel1.Layout()
        bSizer2.Fit( self.m_panel1 )
        bSizer1.Add( self.m_panel1, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel2 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer3 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_staticText2 = wx.StaticText( self.m_panel2, wx.ID_ANY, u"숫자2", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText2.Wrap( -1 )
        bSizer3.Add( self.m_staticText2, 0, wx.ALL, 5 )
        
        self.txtNum2 = wx.TextCtrl( self.m_panel2, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer3.Add( self.txtNum2, 0, wx.ALL, 5 )
        
        
        self.m_panel2.SetSizer( bSizer3 )
        self.m_panel2.Layout()
        bSizer3.Fit( self.m_panel2 )
        bSizer1.Add( self.m_panel2, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel3 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer4 = wx.BoxSizer( wx.VERTICAL )
        
        rdoOpChoices = [ u"+", u"-", u"*", u"/" ]
        self.rdoOp = wx.RadioBox( self.m_panel3, wx.ID_ANY, u"연산자 선택", wx.DefaultPosition, wx.DefaultSize, rdoOpChoices, 1, wx.RA_SPECIFY_ROWS )
        self.rdoOp.SetSelection( 2 )
        bSizer4.Add( self.rdoOp, 0, wx.ALL|wx.EXPAND, 5 )
        
        
        self.m_panel3.SetSizer( bSizer4 )
        self.m_panel3.Layout()
        bSizer4.Fit( self.m_panel3 )
        bSizer1.Add( self.m_panel3, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel4 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer5 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_staticText3 = wx.StaticText( self.m_panel4, wx.ID_ANY, u"연산결과 : ", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText3.Wrap( -1 )
        bSizer5.Add( self.m_staticText3, 0, wx.ALL, 5 )
        
        self.staResult = wx.StaticText( self.m_panel4, wx.ID_ANY, u"0", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.staResult.Wrap( -1 )
        bSizer5.Add( self.staResult, 0, wx.ALL, 5 )
        
        
        self.m_panel4.SetSizer( bSizer5 )
        self.m_panel4.Layout()
        bSizer5.Fit( self.m_panel4 )
        bSizer1.Add( self.m_panel4, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel5 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer6 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.btnCalc = wx.Button( self.m_panel5, wx.ID_ANY, u"계산", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer6.Add( self.btnCalc, 0, wx.ALL, 5 )
        
        self.btnClear = wx.Button( self.m_panel5, wx.ID_ANY, u"초기화", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer6.Add( self.btnClear, 0, wx.ALL, 5 )
        
        self.btnExit = wx.Button( self.m_panel5, wx.ID_ANY, u"종료", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer6.Add( self.btnExit, 0, wx.ALL, 5 )
        
        
        self.m_panel5.SetSizer( bSizer6 )
        self.m_panel5.Layout()
        bSizer6.Fit( self.m_panel5 )
        bSizer1.Add( self.m_panel5, 1, wx.EXPAND |wx.ALL, 5 )
        
        
        self.SetSizer( bSizer1 )
        self.Layout()
        
        self.Centre( wx.BOTH )
        # Connect Events
        self.btnCalc.id  = 1 # id 부여
        self.btnClear.id = 2
        self.btnExit.id  = 3
        self.btnCalc.Bind( wx.EVT_BUTTON, self.OnCalcProcess )
        self.btnClear.Bind( wx.EVT_BUTTON, self.OnCalcProcess )
        self.btnExit.Bind( wx.EVT_BUTTON, self.OnCalcProcess )
    
    def __del__( self ):
        pass
    
    
    # Virtual event handlers, overide them in your derived class
    def OnCalcProcess( self, event ):
        sel_id = event.GetEventObject().id # event 발생 객체의 id를 get
        #print(sel_id)
        if sel_id == 1: # 계산 버튼을 누를 경우
            op = self.rdoOp.GetStringSelection() # 선택된 라디오 버튼의 문자열 get  
            #print(op)
            num1 = self.txtNum1.GetValue()
            num2 = self.txtNum2.GetValue()
            
            if num1 == '' or num2 == '':
                wx.MessageBox('값을 입력하시오', '알림', wx.OK)
                return
            try:
                result = eval(num1 + op + num2)
            except Exception as e:
                wx.MessageBox('연산오류', '알림', wx.OK)
                return
            
            self.staResult.SetLabel(str(result))
        elif sel_id == 2: # 초기화
            self.txtNum1.SetLabel('')
            self.txtNum2.SetLabel('')
            self.staResult.SetLabel('')
            self.rdoOp.SetSelection(0)
            self.txtNum1.SetFocus()     # UX/UI
        elif sel_id == 3:
            dlg = wx.MessageDialog(self, '정말 종료할까요?', '알림', wx.YES_NO) # MessageDialog style 입력
            temp = dlg.ShowModal() # MessageDialog 창 발생 
            if temp == wx.ID_YES:  # YES 버튼을 누를 경우
                dlg.Destroy()      # MessageDialog창 닫기 
                self.Close()       # Frame 닫기
        
if __name__ == '__main__':
    app = wx.App()
    MyFrame1(None).Show()
    app.MainLoop()


25. SQLite

 : 개인용 DB SQLite3 : Python에 기본 설치됨

 : 환경변수 path에 추가 : C:\anaconda3\Library\bin

 * test33_sqlite

import sqlite3
print(sqlite3.version_info)

#conn = sqlite3.connect('example.db')
conn = sqlite3.connect(':memory:') # ram에 DB 생성 - 테스트용으로 연습할 때

try:
    cur = conn.cursor()
    
    cur.execute("create table if not exists friends(name text, phone text)")
    
    cur.execute("insert into friends values('홍길동', '111-1111')")
    cur.execute("insert into friends values(?, ?)", ('tom', '222-2222'))
    conn.commit()
    cur.execute("select * from friends")
    for f in cur:
        print(f[0] + " " + f[1])
    
except Exception as e:
    print(e)
    conn.rollback()
finally:
    conn.close()

26. 원격 DB 연동

 : maria db

 : anaconda prompt : pip install mysqlclient 입력

 * test34_db

import MySQLdb

conn = MySQLdb.connect(host = '127.0.0.1', user = 'root', password='123', database='test')
print(conn)
conn.close

sangdata table 자료 읽기

import MySQLdb

config = {
    'host':'127.0.0.1',
    'user':'root',
    'password':'123',
    'database':'test',
    'port':3306,
    'charset':'utf8',
    'use_unicode':True
}
try:
    conn = MySQLdb.connect(**config)
    cursor = conn.cursor() # sql문 처리용
    
    #자료추가1
    sql = "insert into sangdata(code, sang, su, dan) values(10, '새우깡', 5, 1200)" 
    cursor.execute(sql)
    conn.commit()
    sql = "insert into sangdata values(%s, %s, %s, %s)"
    #sql_data = ('12', '감자깡', 10, 2000)
    sql_data = '12', '감자깡', 10, 2000
    re = cursor.execute(sql, sql_data) # 성공하면 1, 실패시 0
    print(cursor)
    print(re)
    conn.commit()
    # 자료 수정
    sql = "update sangdata set sang=%s, su=%s, dan=%s where code=%s"
    sql_data = '깡', 7, 1000, 12
    cou = cursor.execute(sql, sql_data) # 성공하면 n, 실패시 0
    print('성공건수 ',cou)
    conn.commit()
    # 자료삭제
    code = '10'
    sql = "delete from sangdata where code =" + code # 비권장
    cursor.execute(sql)
    sql = "delete from sangdata where code = %s" # 권장 1
    cursor.execute(sql, (code,)) # 튜플
    sql = "delete from sangdata where code = '{0}'".format(code) # 권장 2
    cou = cursor.execute(sql)
    print('성공건수 ',cou)
    conn.commit()
    # 자료읽기 1
    sql = "select code, sang, su, dan from sangdata"
    cursor.execute(sql)    # DB의 자료를 읽어 cursor 객체가 그 결과를 기억
    
    for data in cursor.fetchall():
        #print(data)
        print('%s %s %s %s'%data)
    # 자료읽기 2
    for r in cursor:
        print(r[0], r[1], r[2], r[3])
    # 자료읽기 3
    for (code, sang, su, dan) in cursor:
        print(code, sang, su, dan)
    
    for (a, b, c, d) in cursor:
        print(a, b, c, d)
except MySQLdb.connections.Error as err:
    print('db err' + str(err))
except Exception as e:
    print('err' + str(e))
finally:
    cursor.close()
    conn.close()

 

 - 키보드로 부서번호를 입력받아 해당 부서에 근무하는 직원 출력

 * test35_db

import MySQLdb
import sys

config = {
    'host':'127.0.0.1',
    'user':'root',
    'password':'123',
    'database':'test',
    'port':3306,
    'charset':'utf8',
    'use_unicode':True
}

try:
    conn = MySQLdb.connect(**config)
    cursor = conn.cursor()
    
    buser_no = input('부서번호 입력 : ')
    sql = """
    select jikwon_no, jikwon_name, buser_num, jikwon_jik, jikwon_pay
    from jikwon
    where buser_num ={0}
    """.format(buser_no)
    
    cursor.execute(sql)
    datas = cursor.fetchall()
    
    if len(datas) == 0:
        print(str(buser_no)+ '번 부서는 없습니다.')
        sys.exit()
        
    for d in datas:
        print(d[0], d[1], d[2], d[3])
        
    print('인원수 : ' + str(len(datas)))
    
except Exception as e:
    print('err', e)
    
finally:
    cursor.close()
    conn.close()

 * test36_db_gui

config = {
    'host':'127.0.0.1',
    'user':'root',
    'password':'123',
    'database':'test',
    'port':3306,
    'charset':'utf8',
    'use_unicode':True
}

 - 파일 분리

import ast

with open('mariadb.txt', mode = 'r') as f:
    #print(f.read())
    aa = f.read()
    config = ast.literal_eval(aa)
import wx
import wx.xrc
import MySQLdb

class MyGogek ( wx.Frame ):
    
    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"고객자료 보기", pos = wx.DefaultPosition, size = wx.Size( 500,336 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
        
        #self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
        self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_MENU ) )
        
        bSizer1 = wx.BoxSizer( wx.VERTICAL )
        
        self.m_panel1 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer2 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_staticText1 = wx.StaticText( self.m_panel1, wx.ID_ANY, u"사번 : ", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText1.Wrap( -1 )
        bSizer2.Add( self.m_staticText1, 0, wx.ALL, 5 )
        
        self.txtNo = wx.TextCtrl( self.m_panel1, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer2.Add( self.txtNo, 0, wx.ALL, 5 )
        
        self.m_staticText2 = wx.StaticText( self.m_panel1, wx.ID_ANY, u"직원명", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText2.Wrap( -1 )
        bSizer2.Add( self.m_staticText2, 0, wx.ALL, 5 )
        
        self.txtName = wx.TextCtrl( self.m_panel1, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer2.Add( self.txtName, 0, wx.ALL, 5 )
        
        self.btnLogin = wx.Button( self.m_panel1, wx.ID_ANY, u"로그인", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer2.Add( self.btnLogin, 0, wx.ALL, 5 )
        
        
        self.m_panel1.SetSizer( bSizer2 )
        self.m_panel1.Layout()
        bSizer2.Fit( self.m_panel1 )
        bSizer1.Add( self.m_panel1, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel2 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer3 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.staMsg = wx.StaticText( self.m_panel2, wx.ID_ANY, u"고객목록", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.staMsg.Wrap( -1 )
        bSizer3.Add( self.staMsg, 0, wx.ALL, 5 )
        
        
        self.m_panel2.SetSizer( bSizer3 )
        self.m_panel2.Layout()
        bSizer3.Fit( self.m_panel2 )
        bSizer1.Add( self.m_panel2, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel3 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer4 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.lstGogek = wx.ListCtrl( self.m_panel3, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LC_REPORT )
        bSizer4.Add( self.lstGogek, 1, wx.ALL|wx.EXPAND, 5 )
        
        
        self.m_panel3.SetSizer( bSizer4 )
        self.m_panel3.Layout()
        bSizer4.Fit( self.m_panel3 )
        bSizer1.Add( self.m_panel3, 1, wx.EXPAND |wx.ALL, 5 )
        
        self.m_panel4 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer5 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.staCount = wx.StaticText( self.m_panel4, wx.ID_ANY, u"인원수", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.staCount.Wrap( -1 )
        bSizer5.Add( self.staCount, 0, wx.ALL, 5 )
        
        
        self.m_panel4.SetSizer( bSizer5 )
        self.m_panel4.Layout()
        bSizer5.Fit( self.m_panel4 )
        bSizer1.Add( self.m_panel4, 1, wx.EXPAND |wx.ALL, 5 )
        
        
        self.SetSizer( bSizer1 )
        self.Layout()
        
        self.Centre( wx.BOTH )
        
        # lstGogek 객체에 제목 작성
        self.lstGogek.InsertColumn(0, '고객번호', width=100)
        self.lstGogek.InsertColumn(1, '고객명', width=150)
        self.lstGogek.InsertColumn(2, '고객전화', width=200)
        
        # Connect Events
        self.btnLogin.Bind( wx.EVT_BUTTON, self.OnLogin )
    
    def __del__( self ):
        pass
    # Virtual event handlers, overide them in your derived class
    def OnLogin( self, event ):
        if self.txtNo.GetValue() == '': # 사번을 입력안할 경우 팝업 발생
            wx.MessageBox('사번입력', '알림', wx.OK)
            self.txtNo.SetFocus()
            return
        
        if self.txtName.GetValue() == '': # 사번을 입력안할 경우 팝업 발생
            wx.MessageBox('직원명 입력', '알림', wx.OK)
            self.txtNo.SetFocus()
            return
        
        self.LoginCheck()
    def LoginCheck(self):
        try:
            conn = MySQLdb.connect(**config)
            cursor = conn.cursor()
            no = self.txtNo.GetValue()
            name = self.txtName.GetValue()
            #print(no, name)
            
            sql ="""
            select count(*) from jikwon
            where jikwon_no ='{0}' and jikwon_name ='{1}'
            """.format(no, name)
            
            cou = cursor.execute(sql)
            count = cursor.fetchone()[0]
            #print(count) # 1
            if count == 0:
                wx.MessageBox('로그인 실패', '알림', wx.OK)
                return
            else:
                self.staMsg.SetLabelText(no + '번 직원의 관리 고객목록')
                self.DisplayData(no) # 직원자료 출력 메소드 호출
            
        except Exception as e:
            print('LoginCheck err',e)
        finally:
            cursor.close()
            conn.close()
    def DisplayData(self, no):
        try:
            conn = MySQLdb.connect(**config)
            cursor = conn.cursor()
            
            sql = """
            select gogek_no, gogek_name, gogek_tel
            from gogek
            where gogek_damsano = {}
            """.format(no)
            
            cou = cursor.execute(sql)
            datas = cursor.fetchall()
            #print(datas)
            self.lstGogek.DeleteAllItems() # list control 초기화
            for d in datas:
                i = self.lstGogek.InsertItem(1000, 0) # List Control 최대 행수 입력
                self.lstGogek.SetItem(i, 0, str(d[0]))
                self.lstGogek.SetItem(i, 1, d[1])
                self.lstGogek.SetItem(i, 2, d[2])
            self.staCount.SetLabelText('인원수 : ' + str(len(datas)))
        except Exception as e:
            print('DisplayData err',e)
        finally:
            cursor.close()
            conn.close()
            
            
if __name__ == '__main__':
    app = wx.App()
    MyGogek(None).Show()
    app.MainLoop()
    

 - mariadb.txt

{
    'host':'127.0.0.1',
    'user':'root',
    'password':'123',
    'database':'test',
    'port':3306,
    'charset':'utf8',
    'use_unicode':True
}

27. socket

 - Socket : TCP/IP Protocol(통신규약)의 프로그래머 인터페이스를 모듈로 지원

 

 * socket_test

import socket

print(socket.getservbyname('http','tcp'))   # http port 80
print(socket.getservbyname('telnet','tcp')) # http port 23
print(socket.getservbyname('ftp','tcp'))    # http port 21
print(socket.getservbyname('smtp','tcp'))   # http port 25
print(socket.getservbyname('pop3','tcp'))   # http port 110

print()
print(socket.getaddrinfo('www.naver.com', 80, proto=socket.SOL_TCP))
# [(<AddressFamily.AF_INET: 2>, 0, 6, '', ('125.209.222.142', 80)), (<AddressFamily.AF_INET: 2>, 0, 6, '', ('223.130.195.200', 80))]
print(socket.getaddrinfo('www.daum.net', 80, proto=socket.SOL_TCP))

 

 * soc1_server

# 접속상태 확인을 위한 단순 Echo Server - client의 요청에 1회만 반응

from socket import *

serverSock = socket(AF_INET, SOCK_STREAM) # socket(socket 종류, socket 유형)
serverSock.bind(('127.0.0.1', 9999))
serverSock.listen(1)                      # TCP 리스너 설정

print('server start')

conn, addr = serverSock.accept()
print('client addr :', addr)
print('from client message : ', conn.recv(1024).decode())
# 클라이언트로 부터 바이트 단위 문자열로 수신된 내용 출력
conn.close()
serverSock.close()

 

 

 * soc1_client

# 1회 접속용 클라이언트
from socket import *

clientSock = socket(AF_INET, SOCK_STREAM)
clientSock.connect(('127.0.0.1', 9999))
clientSock.sendall('안녕 반가워'.encode(encoding='utf_8', errors='strict'))
clientSock.close()

 * soc2_server

# 서버 서비스 계속 유지
import socket
import sys

HOST = ''
PORT = 8888

serverSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
    serverSock.bind((HOST, PORT))
    print('server start')
    serverSock.listen(5) # 클라이언트 접속 대기. 최대 동시 접속수는 1 ~ 5
    
    while True:
        conn,addr = serverSock.accept() # 클라이언트 접속 승인
        print('client info : ', addr[0], addr[1])
        print(conn.recv(1024).decode()) # 클라이언트가 전송한 메세지 수신 후 출력
        
        # 전송
        conn.send('from server : ' + str(addr[1]) + 'ㅁㅁㅁ'.encode('utf_8'))
except socket.error as err:
    print('socket error : ', err)
except Exception as e:
    print('error : ', e)
finally:
    serverSock.close()
    

 

 * soc2_client

# 1회 접속용 클라이언트
from socket import *

clientSock = socket(AF_INET, SOCK_STREAM)
clientSock.connect(('127.0.0.1', 8888))
clientSock.sendall('안녕 반가워'.encode(encoding='utf_8'))
re_msg = clientSock.recv(1024).decode()
print('수신자료', re_msg)
clientSock.close()

28. Thread

 - process : 실행 중인 응용프로그램을 의미, 프로세스 단위로 별도의 메모리를 사용

from subprocess import *

Popen('calc.exe')
Popen('notepad.exe')

 - thread : Light weight process 라고도 함. 메인 프로세스(스레드)와 병렬적으로 수행되는 단위 프로그램. 스레드 단위로 함수나 메소드를 수행 가능.

 

 * th1

import time

def run(id):
    for i in range(1, 11):
        print('id:{} -> {}'.format(id, i))
        time.sleep(0.5)

  1. thread를 사용하지 않은 경우

run(1) # 순차적으로 호출되므로 순차적으로 처리됨
run(2)

  2. thread를 사용한 경우 : 스레드 스케쥴러에 의해 랜덤하게 스레드 처리가 됨

import threading

th1 = threading.Thread(target=run, args = ('일')) # 사용자 정의 스레드 생성
th2 = threading.Thread(target=run, args = ('이'))
th1.start() # 스레드 수행 시작
th2.start()
th1.join()  # 사용자 정의 스레드가 종료될때까지 메인 스레드 대기 시킴 
th2.join()

print('메인 프로그램 종료') # 메인 스레드에 의해 메인 모듈이 실행(기본 값)

 * th2

스레드를 이용하여 날짜 및 시간 출력

import time
import threading

now = time.localtime()
#print(now)
print('현재는 {0}년 {1}월 {2} 일 {3} 시 {4} 분 {5} 초'.format(now.tm_year, now.tm_mon, \
                                                     now.tm_mday ,now.tm_hour,now.tm_min,now.tm_sec))

def cal_show():
        now = time.localtime()
        print('현재는 {0}년 {1}월 {2} 일 {3} 시 {4} 분 {5} 초'.format(now.tm_year, now.tm_mon, \
                                                     now.tm_mday ,now.tm_hour,now.tm_min,now.tm_sec))

def myRun():
    while True:
        now2 = time.localtime()
        if now2.tm_min == 57:
            break
        cal_show()
        time.sleep(1)
        
th = threading.Thread(target=myRun)
th.start()
th.join()
class MyThread(threading.Thread):
    def run(self):
        for i in range(1, 10):
            print('id{} --> {}'.format(self.getName(), i))
            time.sleep(0.1)
            
ths = []
for i in range(2):
    th = MyThread()
    th.start()
    ths.append(th)
    
for th in ths:
    th.join()
    
print('프로그램 종료')

 - 스레드간 공유자원 값 충돌 방지 - 동기화

 * th3

import threading, time
g_count = 0 # 전역변수는 자동으로 스레드의 공유자원이 됨

lock = threading.Lock()

def threadCount(id, count):
    global g_count
    for i in range(count):
        lock.acquire() # 두 개 이상의 스레드 공유 자원 충돌방지. lock을 걸어 다른 스레드 수행대기.
        print('id %s => count : %s, g_count : %s'%(id, i, g_count))
        g_count += 1
        lock.release() # lock을 해제

for i in range(1, 6):
    threading.Thread(target=threadCount, args =(i, 5)).start()

time.sleep(2)
print('final g_count : ', g_count)
print('finish process')

 - 스레드의 활성화/비활성화

 * th4

import threading, time
bread_plate = 0 # 빵 접시 - 공유자원
lock = threading.Condition()

class Maker(threading.Thread): # 빵 생성자
    def run(self):
        global bread_plate
        
        for i in range(30):
            lock.acquire() # 공유자운 충동방지
            
            while bread_plate >=10:
                print('빵 생산 초과로 대기')
                lock.wait() # 쓰레드 비활성화
                
            bread_plate += 1
            print('빵 생산 후 접시에 담기 : ', bread_plate)
            
            lock.notify() # 쓰레드 활성화
            lock.release()
            time.sleep(0.05)
            
class Eater(threading.Thread): # 빵 소비자
    def run(self):
        global bread_plate
        
        for i in range(30):
            lock.acquire() # 공유자원 충동방지
            
            while bread_plate <1:
                print('빵이 없어 대기')
                lock.wait() # 쓰레드 비활성화
                
            bread_plate -= 1
            print('빵 소비 후 접시의 빵 수 : ', bread_plate)
            
            lock.notify() # 쓰레드 활성화
            lock.release()
            time.sleep(0.07)
mak = []
con = []
for i in range(5): # 빵 생산자 수
    mak.append(Maker())
    
for i in range(5): # 빵 소비자 수
    con.append(Eater())
    
for th1 in mak:
    th1.start()
    
for th2 in con:
    th2.start()
    
for th1 in mak:
    th1.join()
    
for th2 in con:
    th2.join()
    
print('process 끝')

29. 멀티 쓰레드 채팅 프로그램

 : socket, thread 사용

 * chatServer (서버)

import socket
import threading

ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 서버 소켓 생성
ss.bind(('127.0.0.1', 5000))                           # ip에 연결
ss.listen(5)                                           # 동접속자 수 최대 5로 리스너 설정
print('Chatting start')
users = []

def ChatUser(conn):
    name = conn.recv(1024)
    data = '[알림]' + name.decode('utf_8') + '님이 접속하셨습니다.'
    print(data)
    
    try:
        for p in users:                                # 다른 클라이언트에도 접속 메시지 send
            p.send(data.encode('utf_8'))
            
        while True:                                    # 채팅 진행
            msg = conn.recv(1024)                      # 수신한 메세지
            data = '('+name.decode('utf_8') + ') : ' + msg.decode() # 송부자 + 메세지
            print('[R] '+data)
            for p in users:                            # 다른 클라이언트에도 메시지 send
                p.send(data.encode('utf_8'))
    except Exception as e:                             # 접속 종료 시
        users.remove(conn)                             # 접속 종료 시 list에 conn 제거
        data = '[알림]' + name.decode('utf_8') + '님이 접속을 종료하셨습니다.'
        print(data)
        print(e)
        if users:                                      # 다른 클라이언트에도 접속 종료 메시지 send
            for p in users:
                p.send(data.encode('utf_8'))
        else:
            print('exit')
    
while True:
    conn, addr = ss.accept()                           # 소켓 접속 및 대기. 클라이언트 접속 시 값 리턴
    users.append(conn)                                 # 접속 시 list에 conn 추가
    th = threading.Thread(target=ChatUser, args = (conn, )) # 접속자 수 만큼 쓰레드 생성
    th.start()

 

 * chatClient (클라이언트)

import socket
import threading
import sys
def Handle(socket):
    while True:
        data = socket.recv(1024)
        if not data: continue
        print(data.decode('utf_8'))                    # 파이썬 표준 출력은 버퍼링 된다.
        #print(data.decode('utf_8', flush=true))
        
sys.stdout.flush()                                     # 표준 입출력 버퍼 비움

cs = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 클라이언트 소켓 생성
cs.connect(('127.0.0.1', 5000))                        # 해당 ip에 접속

name = input('채팅 아이디 입력 : ')
cs.send(name.encode('utf_8'))                          # 접속 id send

th = threading.Thread(target=Handle, args = (cs,))     # 쓰레드 생성
th.start()

while True:
    msg = input()                                      # 채팅 메세지 입력
    sys.stdout.flush()
    
    if not msg:continue
    cs.send(msg.encode('utf_8'))                       # msg가 있을 경우 msg send

cs.close()

 


30. pool

GIL(Global Interpreter Lock) 파이썬 인터프리터가 한 스레드만 하나의 바이트코드를 실행 시킬 수 있도록 해주는 Lock
하나의 스레드에 모든 자원을 허락하고 그 후에는 Lock을 걸어 다른 스레드는 실행할 수 없게 막아버린다.
그런 이유로 구조적으로 충돌이 발생하는 경우가 발생한다.
이에 개선사항으로 멀티 프로세싱 모듈 지원한다.

Pool : 압력 값에 대해 process들을 건너건너 분배하여 함수 실행을 병렬하는 방법
PID : process id

 

 * 07_multi_pool

from multiprocessing import Pool
import time 
import os
def f(x):
    print('값', x, '에 대한 작업 pid', os.getpid()) # 현재 진행 중인 process의 processId를 반환
    time.sleep(1)
    return x * x

if __name__ == '__main__':
    p = Pool(3) # pool 객체 생성. 프로세스 수 3 ~ 5 권장
    startTime = int(time.time())
    
    
    for i in range(0, 10): # 0 ~ 9
        print(f(i)) # 10
    
    # 값 0 에 대한 작업 pid 75580
    # 0
    # 값 1 에 대한 작업 pid 75580
    # 1
    # 값 2 에 대한 작업 pid 75580
    # 4
    # 값 3 에 대한 작업 pid 75580
    # 9
    # 값 4 에 대한 작업 pid 75580
    # 16
    # 값 5 에 대한 작업 pid 75580
    # 25
    # 값 6 에 대한 작업 pid 75580
    # 36
    # 값 7 에 대한 작업 pid 75580
    # 49
    # 값 8 에 대한 작업 pid 75580
    # 64
    # 값 9 에 대한 작업 pid 75580
    # 81
    # 총 작업 시간 :  10
    
    print(p.map(f, range(0, 10))) # 함수와 인자값을 매핑하면서 데이터를 분배처리
    # 값 0 에 대한 작업 pid 75712
    # 값 1 에 대한 작업 pid 75604
    # 값 2 에 대한 작업 pid 75540
    # 값 3 에 대한 작업 pid 75712
    # 값 4 에 대한 작업 pid 75604
    # 값 5 에 대한 작업 pid 75540
    # 값 6 에 대한 작업 pid 75712
    # 값 7 에 대한 작업 pid 75604
    # 값 8 에 대한 작업 pid 75540
    # 값 9 에 대한 작업 pid 75712
    # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    # 총 작업 시간 :  5
    endTime = int(time.time())
    print('총 작업 시간 : ', (endTime - startTime))

 


31. process

멀티 프로세실을 위한 Process 클래스
하나의 프로세스를 하나의 함수에 적당한 인자값을 할당해주고 (없을 수도 있음) 진행

 

 * 08_multi_process

import time
import os
from multiprocessing import Process

def func():
    print('연속 진행하고자 하는 어떤 작업')
    #time.sleep(1)

def doubler(number):
    result = number + 10
    func()
    proc = os.getpid()
    print('number : {0}, number : {1},  process id : {2}'.format(number, result, proc))
    
if __name__ == '__main__':
    numbers = [1, 2, 3, 4, 5]
    procs = []
    
    for index, number in enumerate(numbers):
        proc = Process(target = doubler, args = (number, ))
        procs.append(proc) # Process에 join() 추가할 의도
        proc.start() # doubler 함수가 호출
        
    for proc in procs:
        proc.join()
# 연속 진행하고자 하는 어떤 작업
# number : 1, number : 11,  process id : 11880
# 연속 진행하고자 하는 어떤 작업
# number : 2, number : 12,  process id : 59068
# 연속 진행하고자 하는 어떤 작업
# number : 3, number : 13,  process id : 55000
# 연속 진행하고자 하는 어떤 작업
# number : 4, number : 14,  process id : 74932
# 연속 진행하고자 하는 어떤 작업
# number : 5, number : 15,  process id : 55096

32. 웹 크롤링

멀티 프로세싱을 통한 웹 크롤링 연습 1 - 멀티 프로세싱 없이 작업

 * 09_multi_web1

import requests
from bs4 import BeautifulSoup as bs
# html, xml 지원, json 지원x
import time

def get_links(): # 해당 컨텐츠의 a tag 얻기
    data = requests.get("https://beomi.github.io/beomi.github.io_old/").text
    soup = bs(data, 'html.parser')
    my_titles = soup.select('h3 > a')
    data = []
    
    for title in my_titles:
        data.append(title.get('href')) # a tag의 속성 중 href 값 반환
    
    return data

def get_content(link):
    abs_link = "https://beomi.github.io" + link
    req = requests.get(abs_link)
    html = req.text
    soup = bs(html, 'html.parser')
    print(soup.select('h1')[0].text) # 첫번째 h1 tag의 문자열 출력    
    
if __name__ == '__main__':
    #print(get_links())
    #print(len(get_links())) # 26
    start_time = time.time()
    for link in get_links():
        get_content(link)
        
    end_time = time.time()
    print('소요시간 : %s 초'%(end_time- start_time))
    
# 나만의 웹 크롤러 만들기(4): Django로 크롤링한 데이터 저장하기
# 나만의 웹 크롤러 만들기(3): Selenium으로 무적 크롤러 만들기
# Django에 Social Login 붙이기: Django세팅부터 Facebook/Google 개발 설정까지
# Django에 Custom인증 붙이기
# 나만의 웹 크롤러 만들기(2): Login with Session
# 나만의 웹 크롤러 만들기 with Requests/BeautifulSoup
# Celery로 TelegramBot 알림 보내기
# Virtualenv/VirtualenvWrapper OS별 설치&이용법
# [DjangoTDDStudy] #02: UnitTest 이용해 기능 테스트 하기
# [DjangoTDDStudy] #01: 개발환경 세팅하기(Selenium / ChromeDriver)
# [DjangoTDDStudy] #00: 스터디를 시작하며
# Fabric Put 커맨드가 No Such File Exception을 반환할 때 해결법
# CKEditor의 라이센스와 오픈소스 라이센스
# ReactNative The Basis 번역을 끝냈습니다.
# [React Native 번역]#01: 시작하기
# [번역] 장고(Django)와 함께하는 Celery 첫걸음
# Chrome Native Adblockr 대체하기
# CustoMac 설치 분투기
# Ubuntu14.04에 OhMyZsh 설치
# Ubuntu14.04에서 pip로 mysqlclient 설치 실패시
# Ubuntu14.04에서 Python3기반 virtualenvwrapper 설치
# mac OS X에서 pip virtualenvwrapper 설치 시 uninstalling six 에서 Exception 발생 시
# Fabric for Python3 (Fabric3)
# Windows에서 pip로 mysqlclient 설치 실패시(python3.4/3.5)
# 맥에서 윈도RDP로 접속시 한영전환하기.
# pip로 mysqlclient설치 중 mac os x에서 egg_info / OSError 발생시 대처방법
# 소요시간 : 7.727251768112183 초

 

멀티 프로세싱을 통한 웹 크롤링 연습 2 - 멀티 프로세싱 사용

 * 10_multi_web2

import requests
from bs4 import BeautifulSoup as bs
import time
from multiprocessing import Pool

def get_links(): # 해당 컨텐츠의 a tag 얻기
    data = requests.get("https://beomi.github.io/beomi.github.io_old/").text
    soup = bs(data, 'html.parser')
    my_titles = soup.select('h3 > a')
    data = []
    
    for title in my_titles:
        data.append(title.get('href')) # a tag의 속성 중 href 값 반환
    
    return data

def get_content(link):
    abs_link = "https://beomi.github.io" + link
    req = requests.get(abs_link)
    html = req.text
    soup = bs(html, 'html.parser')
    print(soup.select('h1')[0].text) # 첫번째 h1 tag의 문자열 출력    
    
if __name__ == '__main__':
    start_time = time.time()
#     for link in get_links():
#         get_content(link)
    
    pool = Pool(processes = 4)
    pool.map(get_content, get_links())
        
    end_time = time.time()
    print('소요시간 : %s 초'%(end_time- start_time))
    
# Django에 Social Login 붙이기: Django세팅부터 Facebook/Google 개발 설정까지
# 나만의 웹 크롤러 만들기(4): Django로 크롤링한 데이터 저장하기
# Celery로 TelegramBot 알림 보내기
# 나만의 웹 크롤러 만들기(2): Login with Session
# 나만의 웹 크롤러 만들기(3): Selenium으로 무적 크롤러 만들기
# Django에 Custom인증 붙이기
# 나만의 웹 크롤러 만들기 with Requests/BeautifulSoup
# Virtualenv/VirtualenvWrapper OS별 설치&이용법
# [DjangoTDDStudy] #00: 스터디를 시작하며
# [DjangoTDDStudy] #02: UnitTest 이용해 기능 테스트 하기
# CKEditor의 라이센스와 오픈소스 라이센스
# [React Native 번역]#01: 시작하기
# Fabric Put 커맨드가 No Such File Exception을 반환할 때 해결법
# [DjangoTDDStudy] #01: 개발환경 세팅하기(Selenium / ChromeDriver)
# ReactNative The Basis 번역을 끝냈습니다.
# [번역] 장고(Django)와 함께하는 Celery 첫걸음
# Ubuntu14.04에 OhMyZsh 설치
# Chrome Native Adblockr 대체하기
# Ubuntu14.04에서 Python3기반 virtualenvwrapper 설치
# Fabric for Python3 (Fabric3)
# Ubuntu14.04에서 pip로 mysqlclient 설치 실패시
# CustoMac 설치 분투기
# mac OS X에서 pip virtualenvwrapper 설치 시 uninstalling six 에서 Exception 발생 시
# Windows에서 pip로 mysqlclient 설치 실패시(python3.4/3.5)
# 맥에서 윈도RDP로 접속시 한영전환하기.
# pip로 mysqlclient설치 중 mac os x에서 egg_info / OSError 발생시 대처방법
# 소요시간 : 3.3195197582244873 초

33. HttpServer

HttpServer 구축용 클래스를 이용해 웹서버 서비스 하기
HTTPServer : 기본적인 socket 연결을 관리하는 클래스
SimpleHTTPRequestHandler : get, head 요청만 처리가능

 * 01_httpServer1

from http.server import SimpleHTTPRequestHandler, HTTPServer

PORT = 7777

handler = SimpleHTTPRequestHandler
serv = HTTPServer(('127.0.0.1', PORT), handler) # HTTPServer 서버 객체 생성
print('HTTPServer 서비스 시작')
serv.serve_forever()                            # HTTPServer 서비스 시작

 * index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>파이썬</h2>
<a href="https://daum.net">DAUM 접속</a>
<br>
<a href="bbb.html">bbb 문서</a>
<hr>
바닥글. 작성자 : <b style="font-family : 궁서">홍길동</b>
</body>
</html>

* bbb.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
단순웹 운영중<br>
<input type = "button" value = "이전으로" onclick="history.back()">
</body>
</html>


34. CGI

CGI(Common Gateway Interface)란 웹서버(정보제공측)와 클라이언트(정보이용측)간에 필요한 정보교환을 가능하게 해주는 일종의 웹인터페이스라고(일종의 프로그램) 할 수 있습니다.
PHP, ASP, ASP.NET, JSP...
CGI를 지원하는 CGIHTTPRequestHandler를 사용하면 클라이언트와 서버 사이에 자료를 주고 받을 수 있다. py 문서를 처리가능
get, post 요청처리 모두 지원

 

 * 01_httpServer2

from http.server import CGIHTTPRequestHandler, HTTPServer

PORT = 8888

class HandlerClass(CGIHTTPRequestHandler):
    cgi_directories = ['/cgi-bin']

serv = HTTPServer(('127.0.0.1', PORT), HandlerClass) # HTTPServer 서버 객체 생성

print('HTTPServer 서비스 시작')
serv.serve_forever()                            # HTTPServer 서비스 시작

 

 * main.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>메인 페이지</h1>
<ul>
	<li><a href="https://www.naver.com">네이버</a></li>
	<li><a href="cgi-bin/hello.py">hello.py</a></li>
	<li><a href="cgi-bin/world.py">world.py</a></li>
	<li><a href="cgi-bin/my.py?name=tom&age=23">my.py - get방식으로 자료 전달</a></li>
	<li><a href="friend.html">friend</a></li>
	<li><a href="cgi-bin/sangpum.py">상품자료 확인</a></li>
</ul>
</body>
</html>

 * hello

# 웹 서비스가 가능한 파이썬 파일 작성
ss = '파이썬 변수'
kbs = 9
mbc = 10 + 1.0
print('Content-Type:text/html;charset=utf-8\n')
print('<html>')
print('<body>')
print('<h2>파이썬 문서로 정보 전달</h2>')
print('<b><i>hi</i></b>')
print('<br>파이썬 변수 출력 : %s, %d, %f'%(ss, kbs, mbc))
print('</body>')
print('</html>')

 

 * world

s1 = "자료1"
s2 = "자료2"
print('Content-Type:text/html;charset=utf-8\n')
print("""
<html>
<body>
<h2>html문서 좀더 쉽게 작성</h2>
자료 출력 : {0}, {1}
<br>
<img src='../images/pic.png' width='60%' />
<br>
<a href='../main.html'>메인</a>
</body>
</html>
""".format(s1, s2))

 

 * my

#client가 server로 자료 전달
import cgi

# 사용자(client)가 입력한 자료 받기 - get
form = cgi.FieldStorage()
name = form['name'].value
age = form['age'].value

print('Content-Type:text/html;charset=utf-8\n')
print("""
<html>
<body>
사용자가 입력한 자료 <br>
이름 : {0},
나이 : {1}
</body>
</html>
""".format(name, age))

 * friend.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
친구 자료 입력<p/>
<form action="cgi-bin/friend.py" method="post">
이름 : <input type="text" name ="name" value="홍길동"/><br>
전화 : <input type="text" name ="phone"/><br>
성별 : 
<input type="radio" name="gen" value="남" checked="checked"/>남자
<input type="radio" name="gen" value="여"/>여자<br>
<br>
<input type="submit" value="전송">
</form>
</body>
</html>

 

 * friend.py

import cgi

# 사용자(client)가 입력한 자료 받기 - post
form = cgi.FieldStorage()
name = form['name'].value
phone = form['phone'].value
gen = form['gen'].value

# 값으로 DB저장, 연산에 참여 작업 진행필요.
# 단순 출력 진행.
print('Content-Type:text/html;charset=utf-8\n')
print("""
<html>
<body>
이름 : {}<br>
전화번호 : {}<br>
성별 : {}<br>
</body>
</html>
""".format(name, phone, gen))

 * sangpum

# Maria DB의 sangpum table 자료를 웹으로 출력

import MySQLdb
import ast

with open('cgi-bin/mariadb.txt', mode='r') as f:
    config = ast.literal_eval(f.read())
print('Content-Type:text/html;charset=utf-8\n')
print('<html><body><h2>상품자료 (Python 서버이용)</h2>')
print('<table border="1">')
print('<tr><th>코드</th><th>품명</th><th>수량</th><th>단가</th></tr>')
try:
    conn = MySQLdb.connect(**config)
    cursor = conn.cursor()
    cursor.execute("select * from sangdata")
    datas = cursor.fetchall()
    
    for code, sang, su, dan in datas:
        print("""<tr>
        <td>{0}</td>
        <td>{1}</td>
        <td>{2}</td>
        <td>{3}</td>
        </tr>""".format(code, sang, su, dan)) 
except Exception as e:
    print('error',e)
finally:
    cursor.close()
    conn.close()

print('</table></html></body>')

 


35. 챗봇(chatbot)

 

① 사이트 접속 후 파일 다운로드

www.lfd.uci.edu/~gohlke/pythonlibs/#jpype

 

Python Extension Packages for Windows - Christoph Gohlke

by Christoph Gohlke, Laboratory for Fluorescence Dynamics, University of California, Irvine. Updated on 14 February 2021 at 04:31 UTC. This page provides 32- and 64-bit Windows binaries of many scientific open-source extension packages for the official CPy

www.lfd.uci.edu

[JPype1-1.2.0-cp38-cp38-win_amd64.whl] Download

 

② anaconda prompt 접속 후 명령어 입력
cd C:\Users\wonh\Downloads
pip install JPype1-1.2.0-cp38-cp38-win_amd64.whl

pip install --upgrade pip
pip install konlpy

 

 

 * main.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>메인 페이지</h1>
<ul>
	<li>인사관리</li>
	<li>영업관리</li>
	<li>게시판</li>
	<li><a href="cgi-bin/chatbot.py">챗봇</a></li>
</ul>
<pre>
본문
</pre>
<hr>
<footer>바닥글</footer>
</body>
</html>

 * httpServer

# 챗봇용 서버
from http.server import CGIHTTPRequestHandler, HTTPServer

PORT = 8080

class HandlerClass(CGIHTTPRequestHandler):
    cgi_directories = ['/cgi-bin']

serv = HTTPServer(('127.0.0.1', PORT), HandlerClass) # HTTPServer 서버 객체 생성

print('챗봇용 HTTPServer 서비스 시작')
serv.serve_forever()                            # HTTPServer 서비스 시작

 

 * chatbot

import cgi
from botengine import make_reply

# 입력 양식의 글자 추출하기 --- 
form = cgi.FieldStorage()

# 메인 처리 --- 
def go_main():
    m = form.getvalue("m", default="")
    if m == "" : 
        show_form()
    elif m == "say" : 
        api_say()

# 사용자의 입력에 응답하기 --- 
def api_say():
    print("Content-Type: text/plain; charset=utf-8")
    print("")
    txt = form.getvalue("txt", default="")
    if txt == "": 
        return
    res = make_reply(txt)
    print(res)

# 입력 양식 출력하기 --- 
def show_form():
    print("Content-Type: text/html; charset=utf-8")
    print("")
    print("""
    <html><meta charset="utf-8"><body>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <style>
        h1{ background-color: #ffe0e0; }
        div{ padding:10px; }
        span{ border-radius: 10px; background-color: #ffe0e0; padding:8px; }
        .bot{ text-align: left; }
        .usr{ text-align: right; }
    </style>
    <h1>* 대화하기 *</h1>
    <div id="chat"></div>
    <div class='usr'>
      <input id="txt" size="40">
      <button onclick="say()">전송</button>
    </div>
    <script>
    var url = "./chatbot.py";
    function say() {
      var txt = $('#txt').val();
      $.get(url, {"m":"say","txt":txt},
        function(res) {
          var html = "<div class='usr'><span>" + esc(txt) +
            "</span>: 나</div><div class='bot'> 봇:<span>" + esc(res) + "</span></div>";
          $('#chat').html($('#chat').html()+html);
          $('#txt').val('').focus();
        });
    }
    function esc(s) {
        return s.replace('&', '&amp;').replace('<','&lt;').replace('>', '&gt;');
    }
    </script></body></html>
    """)

go_main()

 

 * botengine

import codecs
from bs4 import BeautifulSoup
import urllib.request
from konlpy.tag import Okt
import os, re, json, random

dict_file = "chatbot-data.json"
dic = {}
twitter = Okt()

# 딕셔너리에 단어 등록하기 --- 
def register_dic(words):
    global dic
    if len(words) == 0: return
    tmp = ["@"]
    for i in words:
        word = i[0]
        if word == "" or word == "\r\n" or word == "\n": continue
        tmp.append(word)
        if len(tmp) < 3: continue
        if len(tmp) > 3: tmp = tmp[1:]
        set_word3(dic, tmp)
        if word == "." or word == "?":
            tmp = ["@"]
            continue
    # 딕셔너리가 변경될 때마다 저장하기
    json.dump(dic, open(dict_file,"w", encoding="utf-8"))

# 딕셔너리에 글 등록하기
def set_word3(dic, s3):
    w1, w2, w3 = s3
    if not w1 in dic: dic[w1] = {}
    if not w2 in dic[w1]: dic[w1][w2] = {}
    if not w3 in dic[w1][w2]: dic[w1][w2][w3] = 0
    dic[w1][w2][w3] += 1

# 문장 만들기 --- 
def make_sentence(head):
    if not head in dic: return ""
    ret = []
    if head != "@": 
        ret.append(head)        
    top = dic[head]
    w1 = word_choice(top)
    w2 = word_choice(top[w1])
    ret.append(w1)
    ret.append(w2)
    while True:
        if w1 in dic and w2 in dic[w1]:
            w3 = word_choice(dic[w1][w2])
        else:
            w3 = ""
        ret.append(w3)
        if w3 == "." or w3 == "? " or w3 == "": 
            break
        w1, w2 = w2, w3
        
    ret = "".join(ret)
    
    # 띄어쓰기
    params = urllib.parse.urlencode({
        "_callback": "",
        "q": ret
    })
    
    # 네이버의 맞춤법 검사기 api를 사용
    data = urllib.request.urlopen("https://m.search.naver.com/p/csearch/ocontent/spellchecker.nhn?" + params)
    data = data.read().decode("utf-8")[1:-2]
    data = json.loads(data)
    data = data["message"]["result"]["html"]
    data = soup = BeautifulSoup(data, "html.parser").getText()
    return data

def word_choice(sel):
    keys = sel.keys()
    return random.choice(list(keys))

# 챗봇 응답 만들기 --- 
def make_reply(text):
    # 단어 학습 시키기
    if not text[-1] in [".", "?"]: text += "."
    words = twitter.pos(text)
    register_dic(words)
    # 사전에 단어가 있다면 그것을 기반으로 문장 만들기
    for word in words:
        face = word[0]
        if face in dic: 
            return make_sentence(face)
    return make_sentence("@")

# 딕셔너리가 있다면 읽어 들이기
if os.path.exists(dict_file):
    dic = json.load(open(dict_file, "r"))


 

 

8. 함수(function)

9. 변수의 생존 범위

10. closure(클로저)

11. 일급함수

12. Module

13. 사용자 정의 모듈

14. turtle

15. 외부 모듈 사용

16. Class

17. 포함관계 (has a 관계)

18. 상속

19. 메소드 오버라이딩


8. 함수(function)

 : 여러개의 명령문을 하나의 묶음으로 만든 실행단위.

* test07_func

 - 내장함수

 - sum(a), bin(a), int(a), float(a), str(a)

print(sum([3, 5, 7]))
print(bin(8))
print(int(1.7), float(7), str(5) + '오')

 

eval(문자열) : 문자열을 계산 

a = 10
b = eval('a + 5')
print(b)

 

zip(a, b) : tuple로 묶어준다.

x = [10, 20, 30]
y = ['a', 'b']
for i in zip(x, y):
    print(i)
# (10, 'a')
# (20, 'b')

 

 

- 사용자 정의 함수

def DoFunc1():
    print('사용자정의 함수 1')
    
print("do1")
DoFunc1()
print("do2")
DoFunc1()
print(DoFunc1)       # 함수 이름은 객체(함수 본체)의 주소를 기억함수
print(type(DoFunc1)) # function
otherFunc = DoFunc1  # 주소 치환
otherFunc()

globals() : 모든 전역 변수 출력

print(globals()) # 모든 전역 변수 출력

 

def DoFunc2(name):
    print('hi', name)
    
DoFunc2('tom')
#DoFunc2('tom', 'tom2') # error
DoFunc2(100)

 

def DoFunc3(ar1, ar2):
    temp = ar1 + ar2
    print('temp', temp)
    # return None # default : None
    #return temp
    a = 2
    if a % 2 ==1:
        return
    else:
        return a
    print('dead')

    
DoFunc3(10, 20)
DoFunc3('kbs', 'mbc')
print(DoFunc3('kbs', 'mbc'))

 

def area_tri(a, b):
    c = a * b / 2
    if a == 0:
        return # 함수 탈출
    area_print(c) # 함수는 함수 호출가능
    
def area_print(c):
    print('삼각형의 넓이는 ',c)

area_tri(20, 30) # 삼각형의 넓이는  300.0

 

def abc():
    pass

 

def exam(a, b):
    ss = str(a) + '+' + str(b) + '=의 답은 : '
    ans = input(ss)
    return a + b == int(ans)

if(exam(5, 2)):
    print('good')
else:
    print('sad')

 

def swap(a, b):
    return b, a

a = 10; b = 20
print(swap(a, b)) # (20, 10)

 

def isOdd(arg):
    return arg % 2 == 1

print(isOdd(3)) # True
print(isOdd(4)) # False

myDict = {x:x*x for x in range(11) if isOdd(x)}
print(myDict) # {1: 1, 3: 9, 5: 25, 7: 49, 9: 81}

9. 변수의 생존 범위

 Local < Enclosing function > Global

* test08_func

player = '전국대표'        # Global Variable

def funcSoccer():
    player = '지역대표'    # Local Variable
    name = '한국인'       # Local Variable
    print(name, player)

funcSoccer()
# print(name, player) # 지역변수는 해당 블록에서만 사용 가능. Error

global a : 블록 내의 지역변수가 아닌 전역변수를 사용하도록 한다.
nonlocal a : 블록 내의 지역변수가 아닌 가까운 함수의 변수를 사용하도록 한다.

a = 10; b = 20; c = 30
print('1) a:{}, b:{}, c:{}'.format(a,b,c))

def Foo():
    a = 40
    b = 50
    def Bar():
        #c = 60
        global c # 블록 내의 지역변수가 아닌 전역변수를 사용하도록 한다.
        nonlocal b # 블록 내의 지역변수가 아닌 가까운 함수의 변수를 사용하도록 한다.
        print('2) a:{}, b:{}, c:{}'.format(a,b,c)) # Enclosing function
        c = 60   # UnboundLocalError: local variable 'c' referenced before assignment
        b = 70
    Bar()

Foo()
#Foo().Bar()
print('3) a:{}, b:{}, c:{}'.format(a,b,c))
print()

 

 - argument 키워드로 매칭

def ShowGugu(start = 1, end = 5):
    print(start, end)

ShowGugu(2, 8)      # 2 8
ShowGugu()          # 1 5
ShowGugu(2)         # 2 5
ShowGugu(start = 2) # 2 5
ShowGugu(end = 10)  # 1 10
ShowGugu(start = 2, end = 7)
ShowGugu(end = 7, start = 2)
#ShowGugu(start = 2, 7) # SyntaxError: positional argument follows keyword argument
ShowGugu(2, end = 7)

 

 - 가변인수 : 인수의 개수가 부정확한 경우

def func1(*ar):
    print(ar)
    for i in ar:
        print('음식 : ' + i)

func1('비비비')
func1('비비비','이이이','트트트트')

 

def func2(a, *ar):
#def func2(*ar, a): # TypeError
    print(a)
    print(ar)
    for i in ar:
        print('음식 : ' + i)

func2('비비비')
func2('비비비','이이이','트트트트')

 

re = 0
def selectProcess(choice, *ar):
    if choice == '+':
        re = 0
        for i in ar:
            re += i
    elif choice == '*':
        re = 1
        for i in ar:
            re *= i
    return re

print(selectProcess('+',1,2,3,4,5))
print(selectProcess('*',1,2,3,4,5))

 

def func3(w, h, **ect):
    print('몸무게 {}, 키 {}'.format(w, h))
    print(ect)
    
func3(65, 175, name = '홍길동')
func3(65, 178, name = '고길동', age = 22)
func3(w=80, h=175, name = '김길동')

 

def func4(a, b, *v1, **v2):
    print(a, b)
    print(v1)
    print(v2)
    
func4(1, 2)
func4(1, 2, 3, 4, 5)
func4(1, 2, 3, 4, 5, k=9, s=5)

10. closure(클로저)

 : 내부 함수의 주소를 반환해서 함수의 멤버를 계속적으로 참조

* test09_closure

def out():
    count = 0
    def inn():
        nonlocal count
        count += 1
        return count
    print(inn())

#print(count)
out() # 1
out() # 1
def outer():
    count = 0
    def inner():
        nonlocal count
        count += 1
        return count
    return inner     # 클로저(내부 함수의 주소를 반환)

obj1 = outer() # inner의 주소를 치환
print(obj1)
print(obj1()) # 1

result = obj1()
print(result) # 2

print(obj1()) # 3
print()

 

 - 수량 * 단가 * 세급 결과 출력

def outer2(tax):
    def inner2(su, dan):
        amount = su * dan * tax
        return amount
    return inner2 # 클로저

q1 = outer2(0.1)  # tax = 0.1
print(q1)
result1 = q1(5, 10000)
print(result1)    # 5000.0

result2 = q1(10, 20000)
print(result2)    # 20000.0

q2 = outer2(0.05) # tax = 0.05
result3 = q2(5, 10000)
print(result3)    # 2500.0

result4 = q2(10, 20000)
print(result4)    # 10000.0

 

 - 재귀함수 - 반복처리

def CountDown(n):
    if n == 0:
        print('처리완료')
    else:
        print(n, end = ' ')
        CountDown(n - 1) # 함수가 자신을 호출
        
CountDown(5) # 5 4 3 2 1 처리완료
def totFunc(su):
    if su == 1:
        print('처리 끝')
        return 1
    return su + totFunc(su - 1)

re = totFunc(10)
print('10까지의 합은 : ', re) # 10까지의 합은 :  55

11. 일급함수

 : 함수 안에 함수 선언 가능, 인자로 함수 사용, 반환값이 함수 가능

def func1(a, b):
    return a + b

func2 = func1      # 함수의 주소를 치환
print(func1(2,3))  # 5
print(func2(2,3))  # 5

def func3(func):   # 인자로 함수 사용
    def func4():   # 함수 안에 함수 선언 가능
        print('내부함수')
    func4()
    return func    # 반환값이 함수 가능

mbc = func3(func1) # func1
print(mbc(3, 4))   # 내부함수 7

 

 - Lambda : 이름이 없는 한 줄짜리 함수
형식 : lambda arg, ... :표현식   => return문 없이 결과 반환

def hap(x, y):
    return x + y
print(hap(2, 4))   # 6

aa = lambda x, y: x + y
print(aa(2, 4))    # 6

kbs = lambda a, su = 10: a + su
print(kbs(5))      # 15
print(kbs(5, 6))   # 11

sbs = lambda a, *tu, **di : print(a, tu, di)
sbs(1,2,3,tvn=3, ytn=24) # 1 (2, 3) {'tvn': 3, 'ytn': 24}

li = [lambda a, b:a+b, lambda a, b:a*b]
print(li[0](3,4))  # 7
print(li[1](3,4))  # 12

 

 - 다른 함수에서 인자 값으로 람다를 사용
filter(함수, 집합형 자료) : 자료의 요소 하나씩를 함수에 입력하여 결과값을 집합형으로 출력

print(list(filter(lambda a: a < 5, range(10))))  # [0, 1, 2, 3, 4]
print(tuple(filter(lambda a: a % 2, range(10)))) # (1, 3, 5, 7, 9)

 

 - 함수 장식자 - meta 기능을 가짐. @함수명

def make2(fn):
    return lambda : 'hi '+ fn()

def make1(fn):
    return lambda : 'hello '+ fn()

def hello():
    return '이이이'

hi = make2(make1(hello))
print(hi()) # hi hello 이이이
print()

@make2
@make1
def hello2():
    return '리리리'

print(hello2()) # hi hello 리리리

hi2 = hello2()
print(hi2)

hi3 = hello2
print(hi3)
print(hi3())

12. Module

 : 소스 코드의 재사용을 가능하게 하며, 소스 코드를 하나의 이름 공간으로 구분하고 관리할 수 있다.
멤버 : 일반 명령문, 함수, 모듈, 클래스
하나의 파일로 처리된다.
내장된 표준 모듈, 사용자 정의 모듈, 제 3자 모듈(third party)

 

* test11_module

 -  내장된 표준 모듈(로딩 필요 없음) 일부 사용해 보기
 작업 중 외부모듈이 필요한 경우 import 모듈명하여 사용

print(sum([2, 3])) # 내장된 표준모듈

import sys
print('모듈 경로 : ',sys.path)
sys.exit() # 프로그램 강제 종료
print('프로그램  종료')
import math
print(math.pi)# 3.141592653589793
print(math.sin(math.radians(30))) # 0.49999999999999994
import calendar
calendar.setfirstweekday(6) # 첫주 시작을 일요일로 변경
calendar.prmonth(2021,2)    # 달력 출력
#    February 2021
# Mo Tu We Th Fr Sa Su
#  1  2  3  4  5  6  7
#  8  9 10 11 12 13 14
# 15 16 17 18 19 20 21
# 22 23 24 25 26 27 28

 

 - 난수 출력

import random
print(random.random())       # 난수 출력 
print(random.randint(1, 10)) # 1~10 사이의 난수

from random import random
print(random())

from random import randint
from random import *
print(randint(1, 10))

13. 사용자 정의 모듈

* test12_my (동일 패키지)

# 사용자 정의 모듈
tot = 123 # 전역변수

def ListHap(*ar):
    print(ar)
    
    if __name__ == "__main__":
        print('응용프로그램이 시작되는 모듈')
    
    
def kbs():
    ch = 9
    print('공영방송', ch)
    
def mbc():
    print('문화방송')

 

* test12_our (다른 패키지)

# 사용자 정의 모듈
def Hap(a, b):
    return a + b

def Cha(a, b):
    return a - b

* test12_our2 (lib폴더 경로)

# 사용자 정의 모듈
def Gop(a, b):
    return a * b

def Nanugi(a, b):
    return a / b

* test12_module

# 사용자 정의 모듈
a = 10
print(a)

def aa():
    print('aa 출력')
    
# 외부 모듈의 멤버 사용하기1
import pack2.test12_my  # 경로

print('tot : ', pack2.test12_my.tot) # tot :  123

li1 =[1, 2]
li2 =[3, 4]
pack2.test12_my.ListHap(li1, li2)


def abc():
    if __name__ == "__main__":
        print('응용프로그램이 시작되는 모듈')
        
abc()

pack2.test12_my.kbs()
print()

# 외부 모듈의 멤버 사용하기2
from pack2 import test12_my
test12_my.mbc() 

from pack2.test12_my import mbc
mbc() 

from pack2.test12_my import mbc, kbs, tot
mbc()
kbs()
print(tot)
print()

# 외부 모듈의 멤버 사용하기3 - package가 다른 경우
from other.test12_our import Hap, Cha
print(Hap(5, 3)) # 8
print(Cha(5, 3)) # 2

# C:\anaconda3\Lib 경로의 모듈 사용
import test12_our2
print(test12_our2.Gop(5, 3))
print(test12_our2.Nanugi(5, 3))

import math
print(math.pi)

from test12_our2 import Gop
print(Gop(5, 3))

from math import pi
print(pi)

window - Preferences - PyDev - Interpreters - Python Interpreters - Libraries Tab 선택 안의 경로에 추가시 import 할 수 있다. 


14. turtle

 : Graphic 지원 모듈 사용 - turtle

* test13_graphic

import turtle
from turtle import *
pen = Pen()
pen.color('red', 'yellow')
pen.begin_fill()
while True:
    pen.forward(200)
    pen.left(170)
    if abs(pen.pos()) < 1:
        break
pen.end_fill()
done()

15. 외부 모듈 사용

* test14

① http://www.lfd.uci.edu/~gohlke/pythonlibs/ 사이트에서 모듈 다운로드하여 lib경로에 설치 

② 시작  - anconda prompt - pip install pygame

import pygame

16. Class

: OOP 기법 구사
: 클래스는 새로운 이름 공간을 지원하는 단위. 멤버는 변수, 메소드, 생성자로 구성. 접근 지정자X, 메소드 오버로딩X

 

* test15_class

print('do')

def func():
    print('함수')
class TestClass: # 원형 클래스  - prototype (객체가 실행과 동시에 생성. new 미사용)
    abc = 1 # 멤버변수(전역변수)
    
    def __init__(self):
        print('생성자')
        
    def __del__(self):
        print('소멸자')
        
    def printMsg(self): # 메소드
        name = '홍길동'
        print(name)
        print(self.abc)
        self.show()
        
    def show(self):
        print('show')
print(TestClass.abc) # 원형 클래스의 멤버 변수 호출
TestClass.printMsg(self) # NameError: name 'self' is not defined
test = TestClass() # 생성자 호출된 후 객체 생성(instance)
# 생성자
print(test.abc) # 1
test.printMsg()          # 1. Bound method call
# 홍길동 1 show
TestClass.printMsg(test) # 2. UnBound Method call
# 홍길동 1 show
print('클래스 타입확인 : ', type(1))    # int
print('클래스 타입확인 : ', type(test)) # __main__.TestClass
print(id(test))      # 2502643056496
print(id(TestClass)) # 2502639316704

 

 * test16_class

class Car:
    handle = 0 # 멤버 변수(필드). 클래스 내 전역
    speed = 0
    
    def __init__(self, name, speed): # 생성자 오버로딩 불가
        self.name = name
        self.speed = speed
        
    def showData(self): # 메소드 오버로딩 불가
        km = ' 킬로미터' # 지역변수
        msg = '속도 : ' + str(self.speed) + km
        return msg
# car1    
car1  = Car('tom', 10)
print(car1.handle, car1.name, car1.speed) # 0 tom 10
car1.color = '핑크'
print('car1.color : ', car1.color)
# car2
car2 = Car('james', 30)
print(car2.handle, car2.name, car2.speed) # 0 james 30
print('car2.color : ', car2.color) # AttributeError: 'Car' object has no attribute 'color'
# __dict__ : 해당 인스턴스의 멤버변수 dict
print(car1.__dict__) # {'name': 'tom', 'speed': 10, 'color': '핑크'}
print(car2.__dict__) # {'name': 'james', 'speed': 30}
# method
print('car1 - ', car1.showData()) # car1 -  속도 : 10 킬로미터
print('car2 - ', car2.showData()) # car2 -  속도 : 30 킬로미터
car1.speed = 100
car2.speed = 200
print('car1 - ', car1.showData()) # car1 -  속도 : 100 킬로미터
print('car2 - ', car2.showData()) # car2 -  속도 : 200 킬로미터
print(Car.speed)  # 0
print(car1.speed) # 100
print(car2.speed) # 200

print(Car.color)  # AttributeError: type object 'Car' has no attribute 'color'
print(car1.color)  # 핑크
print(car2.color) # AttributeError: type object 'Car' has no attribute 'color'

 

* test17_class

kor = 100 # 모듈의 전역변수

def abc():
    print('모듈의 멤버 함수')
    
class MyClass:
    kor = 88
    """
    def __init__(self): # 기본 생성
        pass
    """
    def abc(self):
        print('클래스의 멤버 메소드')
       
    def showData(self):
        print(kor) # 메소드 내에서 없을 경우 모듈의 전역변수를 찾는다. 
        print(self.kor) 
        self.abc() # 현재 클래스 내의 메소드 콜
        abc()      # 모듈의 함수 콜
obj = MyClass()
obj.showData()
# 100
# 88
# 클래스의 멤버 메소드
# 모듈의 멤버 함수
class My:
    a = 1
print(My.a) # 1

my1 = My # 주소
print(my1.a) # 1

my2 = My() # 인스턴스 생성
my2.a = 100
print(my2.a) # 100

my3 = My() # 인스턴스 생성
my3.a = 200
print(my3.a) # 200
my3.b = 123
print(my3.b) # 123

print(My.b)  # Error
print(my1.b) # Error
print(my2.b) # Error

* test18_class

# 클래스 = 설계도
# Singer가 갖추어야 할 기본 속성, 행위를 설계도(원형클래스)로 만든 후 모든 가수들은 Singer type으로 존재하면 됨

class Singer:
    title_song ='노래제목' # 멤버 변수
    
    def __init__(self):
        pass
    
    def sing(self):
        msg = '노래는'
        print(msg, self.title_song)
        
# 편의 상 아래에서 객체를 만들지만 별도의 모듈에서 Singer를 호출하여 사용하는 것이 일반적        
bts = Singer()
bts.sing()              # 노래는 노래제목
bts.title_song = '다이너마이트'
bts.sing()              # 노래는 다이너마이트
bts.co = '빅히트'
print('소속사 :', bts.co) # 소속사 : 빅히트

* test18_class2

# 클래스 연습
print('do')
a = 10
def aa():
    print(a)
    
# 새로운 가수 타입의 객체 필요
import pack2.test18_class

print('-----------------')
twice = pack2.test18_class.Singer()
twice.sing() # 노래는 노래제목
twice.title_song = '우아하게'
twice.sing() # 노래는 우아하게
print('소속사 :', twice.co) # error

17. 포함관계 (has a 관계)

 * test19_handle

# 움직이는 기계에 사용할 부품 클래스

class PohamHandle:
    quantity = 0 # 회전량
    
    def LeftTurn(self, quantify):
        self.quantity = quantify
        return '좌회전'
    
    def RightTurn(self, quantify):
        self.quantity = quantify
        return '우회전'

 

 * test19_car

# Car 클래스 : 여러개의 부품(클래스)을 조립해서 완성된 차를 생성
class PohamCar:
    speed = 0
    turnShow = '정지'
    
    def __init__(self, ownerName):  # ownerName 인스턴트에만 존재. 원형클래스에는 없음
        self.owerName = ownerName
        self.handle = PohamHandle() # 클래스의 포함 관계
        
    def TurnHandle(self, q):        # PohamCar 메소드로 핸들을 움직이는 행위
        if q > 0:
            self.turnShow = self.handle.RightTurn(q)
        elif q < 0:
            self.turnShow = self.handle.LeftTurn(q)
        elif q == 0:
            self.turnShow = '직진'
            
if __name__ == '__main__':
    tom = PohamCar('톰')
    tom.TurnHandle(10)
    print(tom.owerName+'의 회전량은 ' + tom.turnShow + str(tom.handle.quantity)) # 톰의 회전량은 우회전10
    tom.TurnHandle(0)
    print(tom.owerName+'의 회전량은 ' + tom.turnShow) # 톰의 회전량은 우회전10
    print()
    
    oscar = PohamCar('오스카')
    oscar.TurnHandle(-5)
    print(oscar.owerName+'의 회전량은 ' + oscar.turnShow + str(oscar.handle.quantity))
    # 오스카의 회전량은 좌회전-5
    

 * test20_has_a

 - 냉장고(class)에 음식(class)을 저장

class FoodData:
    def __init__(self, name, expiry):
        self.name = name
        self.expiry = expiry
class Fridge:
    isOpend = False # 냉장고 문 개폐 여부
    foods = []      # 리스트
    
    def open(self):
        self.isOpend = True
        print('냉장고 문이 열렸습니다.')
        
    def close(self):
        self.isOpend = False
        print('냉장고 문이 닫혔습니다.')
        
    def put(self, thing):
        if self.isOpend == True:
            self.foods.append(thing) # 클래스의 포함
            print('냉장고에 음식을 저장하였습니다.')
            self.listFood()
        else:
            print('냉장고 문이 닫혀있어 음식을 담을 수 없습니다.')
        
    def listFood(self):
        for f in self.foods:
            print('-', f.name, f.expiry)
f = Fridge()
apple = FoodData('사과', '2021-3-5')
f.put(apple)    # 냉장고 문이 닫혀있어 음식을 담을 수 없습니다.
f.open()        # 냉장고 문이 열렸습니다.
f.put(apple)    # 냉장고에 음식을 저장하였습니다.
                # - 사과 2021-3-5
f.close()       # 냉장고 문이 닫혔습니다.
cola = FoodData('콜라', '2022-12-5')
f.open()        # 냉장고 문이 열렸습니다.
f.put(cola)     # 냉장고에 음식을 저장하였습니다.
                # - 사과 2021-3-5
                # - 콜라 2022-12-5
f.close()       # 냉장고 문이 닫혔습니다.

18. 상속

: 클래스가 다른 클래스의 멤버를 활용 - 상속 : 다형성을 구사

* test21_inherit

class Animal: # 별도의 모듈에서 작성하고 호출하였다고 가정
    age = 0
    
    def __init__(self):
        print('Animal 생성자')
    
    def move(self):
        print('움직이는 생물')
class Dog(Animal): # 상속
    age = 10
    
    def __init__(self):
        print('Dog 생성자')
    
    def dogShow(self):
        age = 2
        print('개')
        print('age :', age)         # 지역변수
        print('age :', self.age)    # 클래스 -> 부모
        print('age :', super().age) # 부모
dog1 = Dog()    # 자식 생성자가 있을 경우 자식 생성자만 수행
                # 자식 생성자가 없을 경우 부모 생성자가 수행
print('dog1.age :',dog1.age) # dog1.age : 0
dog1.move()                  # 움직이는 생물
dog1.dogShow()
# 개
# age : 2
# age : 10
# age : 0
class Horse(Animal):
    pass

horse = Horse()
horse.move()

 클래스 상속 연습

* test22_inherit

class Person:
    say = '사람'
    age = 20
    __kbs = '공영방송' # __변수명 : private 멤버 - 현재 클래스에서만 호출 가능
    
    def __init__(self, age):
        print('Person 생성자')
        self.age = age
        
    def printInfo(self):
        print('나이 :{}, 이야기:{}'.format(self.age, self.say))
    
    def hello(self):
        print('hello')
        print('hello : ', self.say, self.__kbs)
        
        
pe = Person(22) # Person 생성자
pe.printInfo()  # 나이 :22, 이야기:사람
pe.hello()
# hello
# hello :  사람 공영방송
class Employee(Person):
    say = "직원"          # 자식과 동일한 멤버변수에 의해 부모의 say가 숨겨짐
    subject = '근로자'     # Employee 고유 멤버 변수
    
    def __init__(self):
        print("Employee 생성자")
        
    def printInfo(self): # 자식과 동일한 메소드에 의해 부모의 메소드가 숨겨짐. 메소드 오버라이드
        print('Employee printInfo 메소드')
        
    def empShow(self):
        say = "empShow"
        print(say)
        print(self.say)
        self.printInfo()    # 자식 -> 부모
        super().printInfo() # 부모
        

emp = Employee()         # Employee 생성자
print(emp.say, emp.age)  # 직원 20
print(emp.subject)       # 근로자
emp.printInfo()          
# 나이 :20, 이야기:직원
# Employee printInfo 메소드
emp.empShow()
# empShow
# 직원
# Employee printInfo 메소드
# 나이 :20, 이야기:직원
class Worker(Person):
    pass

wo = Worker(33)       # Person 생성자
print(wo.say, wo.age) # 사람 33
wo.printInfo()        # 나이 :33, 이야기:사람
class Worker(Person):
    hobby = '코딩'
    
    def __init__(self, age):
        print('Worker 생성자')
        #super().__init__(age) # 부모의 생성자 호출. Bound call
        Person.__init__(self, age) # UnBound call
    
    def woShow(self):
        self.printInfo()
        super().printInfo()
        
wo = Worker(27)
# Worker 생성자
# Person 생성자
wo.woShow()
# 나이 :27, 이야기:사람
# 나이 :27, 이야기:사람
class Programmer(Worker):
    def __init__(self, age):
        print('Programmer 생성자')
        Worker.__init__(self, age)
        
    def prShow(self):
        self.printInfo()
        super().printInfo()
        
    def kbsShow(self):
        print(self.say)
        #print(self.__kbs) # AttributeError: 'Programmer' object has no attribute '_Programmer__kbs'

pr = Programmer(25)
# Programmer 생성자
# Worker 생성자
# Person 생성자
print(pr.say, pr.age) # 사람 25
pr.prShow()
# 나이 :25, 이야기:사람
# 나이 :25, 이야기:사람
pr.hello()
# hello
# hello :  사람 공영방송
pr.kbsShow()
# 클래스 타입확인
a = 3
print(type(a)) # int
print(type(pr)) # __main__.Programmer
print(Programmer.__bases__) # 부모클래스 확인. __main__.Worker
print(Worker.__bases__) # __main__.Person
print(Person.__bases__) # object

19. 메소드 오버라이딩

: 부모 클래스의 메소드와 동일한 이름의 메소드를 자식 클래스에서 만듦(재정의)
다형성의 근거를 제시

* test23_override

class Parent:
    def printData(self): # 추상 메소드와 유사. 강제하지않음.
        pass
    
    def displayData(self):
        print('Parent의 displayData')
class Child1(Parent):
    def printData(self): # 메소드 오버라이딩
        a = 10
        b = 20
        print(str(a + b) + " 출력")
class Child2(Parent):
    def printData(self):   # override
        print('Child2 printData')
        
    def displayData(self): # override 부모 메소드를 재정의
        print('Child2 displayData')
        
    def c2method(self):    # Child2 고유 메소드
        print('Child2 c2method')
c1 = Child1()
c1.printData()   # 30 출력
c1.displayData() # Parent의 displayData
c2 = Child2()
print()
c2.printData()   # Child2 printData
c2.displayData() # Child2 displayData
print()
# 다형성
par = Parent()
par = c1          # 자식객체의 주소를 치환
par.printData()   # 30 출력
par.displayData() # Parent의 displayData
print()

par = c2          # 자식객체의 주소를 치환
par.printData()   # Child2 printData
par.displayData() # Child2 displayData
par.c2method()    # 오버라이딩 하지않은 메소드도 호출 가능
print()
# 자바와 파이썬 차이
sbs = c1          # 주소 치환시 같은 타입이 아니더라도 객체 및 메소드 사용가능
sbs.printData()
sbs.displayData()
print()
sbs = c2
sbs.printData()
sbs.displayData()
sbs.c2method()
print()

plist = [c1, c2]
for i in plist:
    i.printData()

1. 이클립스에서 파이썬 설치

① 아나콘다 다운로드(파이썬 라이브러리)

www.anaconda.com/

 

Anaconda | The World's Most Popular Data Science Platform

Anaconda is the birthplace of Python data science. We are a movement of data scientists, data-driven enterprises, and open source communities.

www.anaconda.com

product - individual Edition

 

Python 3.8 : 64-Bit Graphical Installer (457 MB) Download

 

Anaconda3-2020.11-Windows-x86_64.exe 관리자 권한으로 실행

 

C:\anaconda3 경로에 설치

 

Add Anaconda3 to my PATH environment variable Uncheck

 

 

② PyDev 설치

 

eclipse - help - eclipse market place - PyDev 검색 - install

 

general - workspace / Web - CSS/HTML/JSP에서 UTF-8로 변경

 

Window - Preferences - PyDev - Interpreters - Phython InterPreter - Browse for python/pypy.exe - C:\anaconda3\Phython.exe 선택 - apply

 

③ 가상환경 설치
시작 - anaconda - anaconda prompt 실행
conda create --name test python=3.7 anaconda 입력
가상환경 활성화 명령 : activate test
가상환경 비활성화 명령 : conda deactivate test

 

④ 주피터 실행 (웹상에 실행)
cd C:\work\psou
python aa.py

jupyter notebook
new - python3

 

⑤ colab

colab.research.google.com/notebooks/intro.ipynb

 

Google Colaboratory

 

colab.research.google.com

 

⑥ 프로젝트 시작

File - New - PyDev - 프로젝트명 입력, 3.8, Python 선택

+ Recent posts

12