мой алгоритм дает плохие кластеры при использовании TF-IDF - PullRequest
0 голосов
/ 30 января 2020

я получаю плохие кластеры. Я хотел бы переписать его таким образом, чтобы я мог просто подключить любой алгоритм, который хотел бы (например, иерархический, knn, k-means) и т.д. c.

#takes in our text_extracts dictionary and returns clusters in an indexed list
def run_clustering(plan):
""" Transform texts to Tf-Idf coordinates and cluster texts using K-Means """
    vectorizer = TfidfVectorizer(tokenizer=process_text,
                             max_df=0.5,
                             min_df=0.005,
                             ngram_range=(1,4),
                             lowercase=True)
#set the model with the vectorizer which will tokenize with our process_text function

extracts = {}
for page in plan.page_list:
    if len(page.text_extract) > 50:
        extracts[str(page.document_id) + '_' + str(page.page_number)] = page.text_extract
extract_lst = [extracts[text] for text in extracts]
tfidf_model = vectorizer.fit_transform(extract_lst)

#determine cluster number with silhouette coefficient
#start with 2 as a cluster size in case the set is very small
num_of_clusters_to_test = [2]

#going to test 25 more sizes in equal intervals based on the number of docs we are clustering
intervals_to_test = int(len(extracts) / 25)

#print(intervals_to_test)
num_of_clusters_to_test += [i for i in range(len(extracts)) if i % intervals_to_test == 0 and i != 0]


#these variables will help us determine the max silhouette
#iters_since_new_max is just being held so that if we aren't reaching optimal size for
#four iterations in a row, we dont have to keep testing huge cluster sizes
max_silhouette_coef = 0
iters_since_new_max = 0
good_size = 2


#cluster with a certain cluster size and record the silhouette coefficient
for size in num_of_clusters_to_test:
    kmeans = KMeans(n_clusters=size).fit(tfidf_model)
    label = kmeans.labels_
    sil_coeff = silhouette_score(tfidf_model, label, metric='euclidean')
    if sil_coeff > max_silhouette_coef:
        max_silhouette_coef = sil_coeff
        good_size = size
        iters_since_new_max = 0
    else:
        iters_since_new_max += 1

    if iters_since_new_max > 4:
        break


# finally cluster for with the good size we want   
km_model = KMeans(n_clusters=good_size)
km_model.fit(tfidf_model)

clustering = collections.defaultdict(list)

for idx, label in enumerate(km_model.labels_):   
    clustering[label].append(idx)


return clustering

оставил как можно больше комментариев, чтобы помочь вам всем понять, за что я иду, может кто-нибудь помочь мне улучшить это

1 Ответ

0 голосов
/ 11 марта 2020

Вы знаете KMeans, если только для чисел c данные, верно. Я имею в виду, не ожидайте, что это сработает на помеченных данных. С KMeans вы вычисляете расстояние до ближайшего центроида (центр кластера) и добавляете эту точку к этому кластеру. Каково «расстояние» между яблоком, бананом и арбузом? Это не имеет смысла! Итак, просто убедитесь, что вы используете KMeans поверх чисел.

import numpy as np 
import pandas as pd 
from pylab import plot,show
from numpy import vstack,array
from scipy.cluster.vq import kmeans,vq
from sklearn.cluster import KMeans
from matplotlib import pyplot as plt
import seaborn as sns

df = pd.read_csv('foo.csv')
# get only numeric fields from your dataframe
df = df.sample(frac=0.1, replace=True, random_state=1)
numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
newdf = df.select_dtypes(include=numerics)

for col in newdf.columns: 
    print(col) 

# your independent variables
X = newdf[['NumericField1','NumericField2','NumericField3','list_price']] 

# your dependent variable
y = newdf['DependentVariable']

# take all numeric features from the corr exercise, and turn into an array
# so we can feed it into a cluetering algorythm
data = np.asarray(newdf)


X = data

# computing K-Means with K = 100 (100 clusters)
centroids,_ = kmeans(data,100)
# assign each sample to a cluster
idx,_ = vq(data,centroids)

# some plotting using numpy's logical indexing
plot(data[idx==0,0],data[idx==0,1],'ob',
     data[idx==1,0],data[idx==1,1],'oy',
     data[idx==2,0],data[idx==2,1],'or',
     data[idx==3,0],data[idx==3,1],'og',
     data[idx==4,0],data[idx==4,1],'om')
plot(centroids[:,0],centroids[:,1],'sg',markersize=8)
show()

details = [(name,cluster) for name, cluster in zip(df.brand,idx)]
for detail in details:
    print(detail)

Я обнаружил, что Affinity Propogation производит гораздо более плотные кластеры, чем KMeans. Вот пример.

# Run Affinity Propogation Experiment    
af = AffinityPropagation(preference=20).fit(X)
cluster_centers_indices = af.cluster_centers_indices_
labels = af.labels_

n_clusters_ = len(cluster_centers_indices)

print('Estimated number of clusters: %d' % n_clusters_)


# plt.scatter(X[:, 0], X[:, 1], s=50)
# Plot result
import matplotlib.pyplot as plt
from itertools import cycle

plt.close('all')
plt.figure(1)
plt.clf()

colors = cycle('bgrcmykbgrcmykbgrcmykbgrcmyk')
for k, col in zip(range(n_clusters_), colors):
    class_members = labels == k
    cluster_center = X[cluster_centers_indices[k]]
    plt.plot(X[class_members, 0], X[class_members, 1], col + '.')
    plt.plot(cluster_center[0], cluster_center[1], 'o', markerfacecolor=col,
             markeredgecolor='k', markersize=14)
    for x in X[class_members]:
        plt.plot([cluster_center[0], x[0]], [cluster_center[1], x[1]], col)

plt.title('Estimated number of clusters: %d' % n_clusters_)
plt.show()

Попробуйте эти концепции и посмотрите, как вы ладите.

...