K- साधन कोहनी, बीआईसी, विचरण समझाया और सिल्हूट के साथ कश्मीर का चयन करने वाला असंगत व्यवहार


23

मैं K- साधनों के साथ 90 विशेषताओं के साथ कुछ वैक्टरों को क्लस्टर करने की कोशिश कर रहा हूं। चूंकि यह एल्गोरिथ्म मुझसे क्लस्टर की संख्या पूछता है, मैं अपनी पसंद को कुछ अच्छे गणित के साथ सत्यापित करना चाहता हूं। मैं 8 से 10 समूहों से होने की उम्मीद करता हूं। विशेषताएं जेड-स्कोर स्केल की गई हैं।

कोहनी विधि और विचरण समझाया

from scipy.spatial.distance import cdist, pdist
from sklearn.cluster import KMeans

K = range(1,50)
KM = [KMeans(n_clusters=k).fit(dt_trans) for k in K]
centroids = [k.cluster_centers_ for k in KM]

D_k = [cdist(dt_trans, cent, 'euclidean') for cent in centroids]
cIdx = [np.argmin(D,axis=1) for D in D_k]
dist = [np.min(D,axis=1) for D in D_k]
avgWithinSS = [sum(d)/dt_trans.shape[0] for d in dist]

# Total with-in sum of square
wcss = [sum(d**2) for d in dist]
tss = sum(pdist(dt_trans)**2)/dt_trans.shape[0]
bss = tss-wcss

kIdx = 10-1

# elbow curve
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(K, avgWithinSS, 'b*-')
ax.plot(K[kIdx], avgWithinSS[kIdx], marker='o', markersize=12, 
markeredgewidth=2, markeredgecolor='r', markerfacecolor='None')
plt.grid(True)
plt.xlabel('Number of clusters')
plt.ylabel('Average within-cluster sum of squares')
plt.title('Elbow for KMeans clustering')

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(K, bss/tss*100, 'b*-')
plt.grid(True)
plt.xlabel('Number of clusters')
plt.ylabel('Percentage of variance explained')
plt.title('Elbow for KMeans clustering')

कोहनी की विधि झगड़ा

इन दो चित्रों से, ऐसा लगता है कि गुच्छों की संख्या कभी नहीं रुकती: डी। अजीब! कोहनी कहाँ है? मैं K कैसे चुन सकता हूं?

बायेसियन सूचना मानदंड

यह विधियां एक्स-साधनों से सीधे आती हैं और बीआईसी का उपयोग करके समूहों की संख्या का चयन करती हैं। एक और रेफरी

    from sklearn.metrics import euclidean_distances
from sklearn.cluster import KMeans

def bic(clusters, centroids):
    num_points = sum(len(cluster) for cluster in clusters)
    num_dims = clusters[0][0].shape[0]
    log_likelihood = _loglikelihood(num_points, num_dims, clusters, centroids)
    num_params = _free_params(len(clusters), num_dims)
    return log_likelihood - num_params / 2.0 * np.log(num_points)


def _free_params(num_clusters, num_dims):
    return num_clusters * (num_dims + 1)


def _loglikelihood(num_points, num_dims, clusters, centroids):
    ll = 0
    for cluster in clusters:
        fRn = len(cluster)
        t1 = fRn * np.log(fRn)
        t2 = fRn * np.log(num_points)
        variance = _cluster_variance(num_points, clusters, centroids) or np.nextafter(0, 1)
        t3 = ((fRn * num_dims) / 2.0) * np.log((2.0 * np.pi) * variance)
        t4 = (fRn - 1.0) / 2.0
        ll += t1 - t2 - t3 - t4
    return ll

def _cluster_variance(num_points, clusters, centroids):
    s = 0
    denom = float(num_points - len(centroids))
    for cluster, centroid in zip(clusters, centroids):
        distances = euclidean_distances(cluster, centroid)
        s += (distances*distances).sum()
    return s / denom

from scipy.spatial import distance
def compute_bic(kmeans,X):
    """
    Computes the BIC metric for a given clusters

    Parameters:
    -----------------------------------------
    kmeans:  List of clustering object from scikit learn

    X     :  multidimension np array of data points

    Returns:
    -----------------------------------------
    BIC value
    """
    # assign centers and labels
    centers = [kmeans.cluster_centers_]
    labels  = kmeans.labels_
    #number of clusters
    m = kmeans.n_clusters
    # size of the clusters
    n = np.bincount(labels)
    #size of data set
    N, d = X.shape

    #compute variance for all clusters beforehand
    cl_var = (1.0 / (N - m) / d) * sum([sum(distance.cdist(X[np.where(labels == i)], [centers[0][i]], 'euclidean')**2) for i in range(m)])

    const_term = 0.5 * m * np.log(N) * (d+1)

    BIC = np.sum([n[i] * np.log(n[i]) -
               n[i] * np.log(N) -
             ((n[i] * d) / 2) * np.log(2*np.pi*cl_var) -
             ((n[i] - 1) * d/ 2) for i in range(m)]) - const_term

    return(BIC)



sns.set_style("ticks")
sns.set_palette(sns.color_palette("Blues_r"))
bics = []
for n_clusters in range(2,50):
    kmeans = KMeans(n_clusters=n_clusters)
    kmeans.fit(dt_trans)

    labels = kmeans.labels_
    centroids = kmeans.cluster_centers_

    clusters = {}
    for i,d in enumerate(kmeans.labels_):
        if d not in clusters:
            clusters[d] = []
        clusters[d].append(dt_trans[i])

    bics.append(compute_bic(kmeans,dt_trans))#-bic(clusters.values(), centroids))

plt.plot(bics)
plt.ylabel("BIC score")
plt.xlabel("k")
plt.title("BIC scoring for K-means cell's behaviour")
sns.despine()
#plt.savefig('figures/K-means-BIC.pdf', format='pdf', dpi=330,bbox_inches='tight')

यहाँ छवि विवरण दर्ज करें

यहाँ एक ही समस्या ... K क्या है?

सिल्हूट

    from sklearn.metrics import silhouette_score

s = []
for n_clusters in range(2,30):
    kmeans = KMeans(n_clusters=n_clusters)
    kmeans.fit(dt_trans)

    labels = kmeans.labels_
    centroids = kmeans.cluster_centers_

    s.append(silhouette_score(dt_trans, labels, metric='euclidean'))

plt.plot(s)
plt.ylabel("Silouette")
plt.xlabel("k")
plt.title("Silouette for K-means cell's behaviour")
sns.despine()

यहाँ छवि विवरण दर्ज करें

Alleluja! यहाँ यह समझ में आता है और यही मैं उम्मीद करता हूँ। लेकिन यह दूसरों से अलग क्यों है?


1
विचरण मामले में घुटने के बारे में आपके प्रश्न का उत्तर देने के लिए, ऐसा लगता है कि यह लगभग 6 या 7 है, आप इसे दो रैखिक सन्निकट खंडों के बीच के वक्र के रूप में कल्पना कर सकते हैं। ग्राफ का आकार असामान्य नहीं है,% विचरण अक्सर asymptotically 100% तक पहुंच जाएगा। मैं आपके BIC ग्राफ में k को थोड़ा कम, लगभग 5.
image_doctor

लेकिन मेरे पास (कमोबेश) सभी तरीकों में समान परिणाम होना चाहिए, है ना?
मार्कोडेना

मुझे नहीं लगता कि मैं कहने के लिए पर्याप्त जानता हूं। मुझे बहुत संदेह है कि तीन विधियां गणितीय रूप से सभी डेटा के बराबर हैं, अन्यथा वे अलग-अलग तकनीकों के रूप में मौजूद नहीं होंगे, इसलिए तुलनात्मक परिणाम डेटा पर निर्भर हैं। तरीकों में से दो क्लस्टर्स की संख्या देते हैं जो करीब हैं, तीसरा अधिक है, लेकिन बहुत अधिक नहीं है। क्या आपके पास समूहों की सही संख्या के बारे में पूर्व सूचना है?
image_doctor 8

मुझे 100% यकीन नहीं है, लेकिन मुझे उम्मीद है कि 8 से 10 कलस्टर तक
marcodena

2
आप पहले से ही "कर्स ऑफ़ डायमेंशनलिटी" के ब्लैक-होल में हैं। एनथिंग्स एक आयामी कमी से पहले काम करता है।
कसरा मंशाई 15

जवाबों:


7

बस उपरोक्त टिप्पणियों और कुछ और विचारों का सारांश पोस्ट करना ताकि यह प्रश्न "अनुत्तरित प्रश्नों" से हटा दिया जाए।

Image_doctor की टिप्पणी सही है कि ये रेखांकन k- साधनों के लिए विशिष्ट हैं। (हालांकि मैं "सिल्हूट" उपाय से परिचित नहीं हूं।) इन-क्लस्टर संस्करण की बढ़ती कश्मीर के साथ लगातार नीचे जाने की उम्मीद है। कोहनी वह जगह है जहां वक्र सबसे अधिक झुकता है। (शायद आपको लगता है कि "2 व्युत्पन्न" अगर आप कुछ गणितीय चाहते हैं।)

आम तौर पर, अंतिम कार्य का उपयोग करके कश्मीर चुनना सबसे अच्छा है। अपने निर्णय लेने के लिए अपने क्लस्टर के सांख्यिकीय उपायों का उपयोग न करें लेकिन अपनी पसंद का मार्गदर्शन करने के लिए अपने सिस्टम के अंतिम-से-अंत प्रदर्शन का उपयोग करें। केवल शुरुआती बिंदु के रूप में आंकड़ों का उपयोग करें।


5

लगातार खंडों के बीच कोणों की गणना करके कोहनी को और अधिक आसान बनाया जा सकता है।

अपना बदलें:

kIdx = 10-1

साथ में:

seg_threshold = 0.95 #Set this to your desired target

#The angle between three points
def segments_gain(p1, v, p2):
    vp1 = np.linalg.norm(p1 - v)
    vp2 = np.linalg.norm(p2 - v)
    p1p2 = np.linalg.norm(p1 - p2)
    return np.arccos((vp1**2 + vp2**2 - p1p2**2) / (2 * vp1 * vp2)) / np.pi

#Normalize the data
criterion = np.array(avgWithinSS)
criterion = (criterion - criterion.min()) / (criterion.max() - criterion.min())

#Compute the angles
seg_gains = np.array([0, ] + [segments_gain(*
        [np.array([K[j], criterion[j]]) for j in range(i-1, i+2)]
    ) for i in range(len(K) - 2)] + [np.nan, ])

#Get the first index satisfying the threshold
kIdx = np.argmax(seg_gains > seg_threshold)

और आप कुछ इस तरह देखेंगे: यहाँ छवि विवरण दर्ज करें

यदि आप seg_gains की कल्पना करते हैं, तो आपको कुछ इस तरह दिखाई देगा: यहाँ छवि विवरण दर्ज करें

मुझे आशा है कि आप अब मुश्किल कोहनी पा सकते हैं :)


3

मैंने एक पायथन लाइब्रेरी बनाई , जो इस तरह के कार्यों में अधिकतम वक्रता के बिंदु का पता लगाने के लिए नाइगल एल्गोरिदम को लागू करने का प्रयास करती है । इसके साथ स्थापित किया जा सकता है pip install kneed

कार्यों के चार अलग-अलग आकार के लिए कोड और आउटपुट:

from kneed.data_generator import DataGenerator
from kneed.knee_locator import KneeLocator

import numpy as np

import matplotlib.pyplot as plt

# sample x and y
x = np.arange(0,10)
y_convex_inc = np.array([1,2,3,4,5,10,15,20,40,100])
y_convex_dec = y_convex_inc[::-1]
y_concave_dec = 100 - y_convex_inc
y_concave_inc = 100 - y_convex_dec

# find the knee points
kn = KneeLocator(x, y_convex_inc, curve='convex', direction='increasing')
knee_yconvinc = kn.knee

kn = KneeLocator(x, y_convex_dec, curve='convex', direction='decreasing')
knee_yconvdec = kn.knee

kn = KneeLocator(x, y_concave_inc, curve='concave', direction='increasing')
knee_yconcinc = kn.knee

kn = KneeLocator(x, y_concave_dec, curve='concave', direction='decreasing')
knee_yconcdec = kn.knee

# plot
f, axes = plt.subplots(2, 2, figsize=(10,10));
yconvinc = axes[0][0]
yconvdec = axes[0][1]
yconcinc = axes[1][0]
yconcdec = axes[1][1]

yconvinc.plot(x, y_convex_inc)
yconvinc.vlines(x=knee_yconvinc, ymin=0, ymax=100, linestyle='--')
yconvinc.set_title("curve='convex', direction='increasing'")

yconvdec.plot(x, y_convex_dec)
yconvdec.vlines(x=knee_yconvdec, ymin=0, ymax=100, linestyle='--')
yconvdec.set_title("curve='convex', direction='decreasing'")

yconcinc.plot(x, y_concave_inc)
yconcinc.vlines(x=knee_yconcinc, ymin=0, ymax=100, linestyle='--')
yconcinc.set_title("curve='concave', direction='increasing'")

yconcdec.plot(x, y_concave_dec)
yconcdec.vlines(x=knee_yconcdec, ymin=0, ymax=100, linestyle='--')
yconcdec.set_title("curve='concave', direction='decreasing'");

यहाँ छवि विवरण दर्ज करें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.