import urllib.request
url = 'https://bit.ly/fruits_300_data'
file_name = 'fruits_300.npy'
urllib.request.urlretrieve(url, file_name)
import numpy as np
fruits = np.load('fruits_300.npy')
fruits_2d = fruits.reshape(-1, 100*100)
plt.imshow(fruits[0], cmap='gray_r')
plt.show()
plt.imshow(fruits[200], cmap='gray')
plt.show()


apple = fruits[0:100].reshape(-1, 100*100)
pineapple = fruits[100:200].reshape(-1, 100*100)
banana = fruits[200:300].reshape(-1, 100*100)
print(apple.mean(axis=1))
plt.hist(np.mean(apple, axis=1), alpha=0.8)
plt.hist(np.mean(pineapple, axis=1), alpha=0.8)
plt.hist(np.mean(banana, axis=1), alpha=0.8)
plt.legend(['apple', 'pineapple', 'banana'])
plt.show()
.mean(axis=1)이므로, 각 행들의 평균값을 계산. => 즉, 각 이미지의 평균 밝기 값. 
fig, axs = plt.subplots(1, 3, figsize=(20, 5))
axs[0].bar(range(10000), np.mean(apple, axis=0))
axs[1].bar(range(10000), np.mean(pineapple, axis=0))
axs[2].bar(range(10000), np.mean(banana, axis=0))
plt.show()

apple_mean = np.mean(apple, axis=0).reshape(100, 100)
pineapple_mean = np.mean(pineapple, axis=0).reshape(100, 100)
banana_mean = np.mean(banana, axis=0).reshape(100, 100)
fig, axs = plt.subplots(1, 3, figsize=(20, 5))
axs[0].imshow(apple_mean, cmap='gray_r')
axs[1].imshow(pineapple_mean, cmap='gray_r')
axs[2].imshow(banana_mean, cmap='gray_r')
plt.show()

abs_diff = np.abs(fruits - apple_mean)
abs_mean = np.mean(abs_diff, axis=(1, 2))
print(abs_mean.shape)
apple_index = np.argsort(abs_mean)[:100]
fig, axs = plt.subplots(10, 10, figsize=(10, 10))
for i in range(10):
for j in range(10):
axs[i, j].imshow(fruits[apple_index[i*10 + j]], cmap='gray_r')
axs[i, j].axis('off')
plt.show()
np.abs(fruits - apple_mean)으로 모든 과일 이미지와 사과 이미지의 평균과 각 픽셀별 절대값 차이를 계산. 여기서 fruits는 (300, 100, 100)의 3차원 배열이고 apple_mean은 (100, 100)짜리 2차원 배열. => 넘파이의 브로드캐스팅으로 배열간 연산 수행. np.mean(abs_diff, axis=(1, 2))으로 abs_diff의 평균을 계산하는데, axis=(1, 2)는 이미지의 세로와 가로 축에 대해 평균을 계산하도록 지정.np.argsort(abs_mean)[:100]: argsort는 배열을 정렬할 때, 해당 요소의 원래 인덱스를 반환. 기본적으로 오름차순으로 정렬하고, 각 원소가 원래 배열에 어디에 위치 했는지를 나타낸다. => 즉, [3, 1, 5, 2]를 argsort하면 [1, 3, 0, 2]가 반환된다. 작은 순서대로 배열된 것의 인덱스가 반환되기 때문에.imshow는 이미지를 표시하는 함수. fruits라는 배열에서 apple_index에서 하나씩 지정해서 그려낸다.
abs_diff = np.abs(fruits - banana_mean)
abs_mean = np.mean(abs_diff, axis=(1, 2))
banana_index = np.argsort(abs_mean)[:100]
fig, axs = plt.subplots(10, 10, figsize=(10, 10))
for i in range(10):
for j in range(10):
axs[i, j].imshow(fruits[banana_index[i*10 + j]], cmap='gray_r')
axs[i, j].axis('off')
plt.show()
abs_diff = np.abs(fruits - pineapple_mean)
abs_mean = np.mean(abs_diff, axis=(1, 2))
pineapple_index = np.argsort(abs_mean)[:100]
fig, axs = plt.subplots(10, 10, figsize=(10, 10))
for i in range(10):
for j in range(10):
axs[i, j].imshow(fruits[pineapple_index[i*10 + j]], cmap='gray_r')
axs[i, j].axis('off')
plt.show()


from sklearn.cluster import KMeans
km = KMeans(n_clusters = 3 , random_state=42)
km.fit(fruits_2d)
print(km.labels_)
print(np.unique(km.labels_, return_counts=True))
KMeans: K 평균 클러스터링을 실행하는 객체.n_clusters는 생성할 클러스터 수 지정. km.labels_: 각 데이터 포인트의 레이블을 담고 있는 속성. fitting을 통해 클러스터링을 수행한 후에 사용할 수 있다. np.unique(return_counts=True): 배열 내의 고유한 값들을 찾아주는 함수고, 여기서 return_counts는 각 고유값이 배열 내에 등장하는 횟수도 반환.
import matplotlib.pyplot as plt
def draw_fruits(arr, ratio=1):
n = len(arr) #n은 샘플 개수
rows = int(np.ceil(n/10)) # 한 줄에 10개씩 이미지
cols = n if rows <2 else 10 # 행이 1개면 열 개수는 샘플 개수, #그렇지 않으면 10개
fig, axs = plt.subplots(rows, cols, figsize=(cols*ratio, rows*ratio), squeeze=False)
for i in range(rows):
for j in range(cols):
if i * 10 + j < n: #n개까지만 그린다
axs[i, j].imshow(arr[i*10+j], cmap='gray_r')
axs[i, j].axis('off')
plt.show()
np.ceil(): 주어진 숫자를 올림한 값으로 반환한다. => np.ceil(n/10)이므로 들어온 배열을 10개씩 하면 몇 줄이 나오는지가 나오고 => int로 정수로. squeeze=는 subplot 배열 시에 축을 압축하지 말고, 행과 열을 2차원으로 명확하게 만들도록. 
draw_fruits(km.cluster_centers_.reshape(-1, 100, 100), ratio=3)
print(km.transform(fruits_2d[100:101]))
km.cluster_centers_: 클러스터링 수행한 후 얻은 클러스터 중심점을 나타내는 배열. 클러스터 중심점은 클러스터링 알고리즘에서 각 클러스터의 대표점. 
km.transform(): 주어진 데이터 포인트(여기선 101번째)와 각 클러스터 중심점 간의 거리를 계산. => 이를 통해 각 데이터 포인트가 각 클러스터에 얼마나 가깝게 속하는지 측정. => 제일 가까운 것으로 분류. inertia = []
for k in range(2, 7):
km = KMeans(n_clusters=k, n_init='auto', random_state=42)
km.fit(fruits_2d)
inertia.append(km.inertia_)
plt.plot(range(2, 7), inertia)
plt.xlabel('k')
plt.ylabel('inertia')
plt.show()
n_init='auto'는 클러스터링 알고리즘이 초기 클러스터 중심점을 설정 방법을 지정하는 매개변수. 기본은 k-means++, random 2가진데, auto는 클러스터 수가 작으면 k-means++, 크면 random을 사용하도록 적용. km.inertia_는 클러스터링 결과의 응집성(inertia)를 나타내는 지표. 각 데이터 포인트와 해당 클러스터의 중심점 간의 거리를 제곱한 값들. 작을수록 더 잘 수행된 것.
import pandas as pd
import glob, os
path = r'C:\Users\~~~\topics'
all_files = glob.glob(os.path.join(path, '*.data'))
filename_list = []
opinion_text = []
for file_ in all_files:
#개별 파일을 읽어서 DataFrame으로 생성
df = pd.read_table(file_, index_col=None, header=0, encoding='latin1')
filename_ = file_.split('\\')[-1]
filename = filename_.split('.')[0]
filename_list.append(filename)
opinion_text.append(df.to_string())
document_df = pd.DataFrame({'filename':filename_list, 'opinion_text':opinion_text})
document_df.head()
r'디렉'으로 하면, 디렉토리 복붙할 때 \ 문제가 해결된다. import nltk
nltk.download('all')
from nltk.stem import WordNetLemmatizer
import nltk
import string
# nltk는 it is ok. ==> 여기서 .제거
remove_punct_dict = dict((ord(punct), None) for punct in string.punctuation)
lemmar = WordNetLemmatizer()
def LemTokens(tokens):
return [lemmar.lemmatize(token) for token in tokens]
def LemNormalize(text):
return LemTokens(nltk.word_tokenize(text.lower().translate(remove_punct_dict)))
ord(): 주어진 문자의 유니코드 포인트를 반환. A는 65. string.punctuation: string(파이썬 문자열 모듈)에 정의된 상수. 모든 문장 부호 문자를 포함하는 문자열. !, ., ?, ! 등. WordNetLemmatizer: 단어 원형 복원(Lemmatization)으로 단어의 기본 형태인 원형을 찾는 과정 => 단어를 문맥에 맞게 변환해 분석하는데 도움이 된다.LemTokens: 토큰 리스트에 대해 단어 복원을 실행해서 그 리스트를 반환하는 함수. 토큰은 일반적으로 문장이나 문서를 단어 단위로 쪼갠 것. LemNormalizetext.lower(): 입력된 텍스트를 모두 소문자로 변환. .translate(remove_punct_dict): 문자열 내에서 각 문자를 지정된 다른 문자로 변환하는 메서드. 위에서 remove_punct_dict는 문장 부호:None으로 정의된 딕셔너리. nltk.word_tokenize(): 주어진 텍스트를 단어 단위로 토큰화해서 반환. from sklearn.feature_extraction.text import TfidfVectorizer
tfidf_vect = TfidfVectorizer(tokenizer=LemNormalize, stop_words='english',
ngram_range=(1, 2), min_df=0.05, max_df=0.85)
#opinion_text 컬럼값으로 feature vectorization 수행
feature_vect = tfidf_vect.fit_transform(document_df['opinion_text'])
TfidVectorizer: 텍스트 데이터를 TF-IDF로 벡터화한다. TF-IDF는 위에 다른 문서에 설명 해놓았고, 요약하면 각 단어의 중요성을 나타내는 수치값.from sklearn.cluster import KMeans
#5개 집합으로 군집화 수행
km_cluster = KMeans(n_clusters=5, max_iter=10000, random_state=0)
km_cluster.fit(feature_vect)
cluster_label = km_cluster.labels_
cluster_centers = km_cluster.cluster_centers_
KMeans로 5개로 나누고, max_iter로 10000번까지 알고리즘 최대 반복 횟수 제한. km_cluster.labels_: 각 데이터 포인트에 할당된 클러스터 레이블을 나타내는 배열. 즉, 각 데이터 포인트가 어떤 클러스터에 속하는지. km_cluster.cluster_centers_: 클러스터 중심 좌표 나타내는 배열. 각 행은 하나의 클러스터, 열은 각 차원의 좌표 => 각 클러스터별로 중심 위치를 특징화하는 좌표. 
# 군집별 top n 핵심단어, 그 단어의 중심 위치 상대값, 대상 파일명들을 반환함.
def get_cluster_details(cluster_model, cluster_data, feature_names, clusters_num, top_n_features=10):
cluster_details = {}
# cluster_centers array 의 값이 큰 순으로 정렬된 index 값을 반환
centroid_feature_ordered_ind = cluster_model.cluster_centers_.argsort()[:,::-1]
#개별 군집별로 iteration하면서 핵심단어, 그 단어의 중심 위치 상대값, 대상 파일명 입력
for cluster_num in range(clusters_num):
# 개별 군집별 정보를 담을 데이터 초기화.
cluster_details[cluster_num] = {}
cluster_details[cluster_num]['cluster'] = cluster_num
# cluster_centers_.argsort()[:,::-1] 로 구한 index 를 이용하여 top n 피처 단어를 구함.
top_feature_indexes = centroid_feature_ordered_ind[cluster_num, :top_n_features]
top_features = [ feature_names[ind] for ind in top_feature_indexes ]
# top_feature_indexes를 이용해 해당 피처 단어의 중심 위치 상댓값 구함
top_feature_values = cluster_model.cluster_centers_[cluster_num, top_feature_indexes].tolist()
# cluster_details 딕셔너리 객체에 개별 군집별 핵심 단어와 중심위치 상대값, 그리고 해당 파일명 입력
cluster_details[cluster_num]['top_features'] = top_features
cluster_details[cluster_num]['top_features_value'] = top_feature_values
filenames = cluster_data[cluster_data['cluster_label'] == cluster_num]['filename']
filenames = filenames.values.tolist()
cluster_details[cluster_num]['filenames'] = filenames
return cluster_details
cluster_model.cluster_centers_.argsort()[:,::-1]: cluster_centers는 각 클러스터의 중심점. => 이걸 argsort로 작은 순부터 인덱스를 반환. [3, 1, 2]면 [1, 2, 0]으로. => 그걸 -1로 해서 큰 순으로 반환.tolist()는 리스트로 바꾸는 메서드. 앞에서 cluster_model은 최초의 입력값이고, cluster_centers에서 [cluster_num, :]은 하나의 클러스터를 골라서 그 중심 벡터를 모두 가져온다. 거기서 top feature index로 값들만 들고 와서 리스트로 바꾼 것.