What does these lines of codes in K_means clustering means? - python

I was learning K-means clustering. And is quite confused about the working of plt.scatter(X[y_kmeans == 0, 0], X[y_kmeans == 0, 1], s = 100, c = 'red', label = 'Cluster 1') what is the purpose of X[y_kmeans == 0, 0], X[y_kmeans == 0, 1] in the code?
Full code here
#k-means
#importing libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
#importing the dataset
dataset = pd.read_csv("mall_customers.csv")
X = dataset.iloc[:,[3,4]].values
#using the elbow method to find the optimal number of clusters
from sklearn.cluster import KMeans
wcss = [] #Within-Cluster Sum of Square
for i in range(1,11):
kmeans = KMeans(n_clusters = i, init = 'k-means++',max_iter = 300,n_init=10,random_state = 0)
kmeans.fit(X)
wcss.append(kmeans.inertia_)
plt.plot(range(1,11),wcss)
plt.title("The elbow method")
plt.xlabel("Number of cluster")
plt.ylabel('Wcss')
plt.show()
#applying kmeans to all dataset
kmeans = KMeans(n_clusters = 5,init = 'k-means++', max_iter=300,n_init=10,random_state=0)
y_kmeans = kmeans.fit_predict(X)
#Visualising the cluster
plt.scatter(X[y_kmeans == 0,0],X[y_kmeans == 0,1],s=100,c = 'red' ,label='Cluster1')
plt.scatter(X[y_kmeans == 1,0],X[y_kmeans == 1,1],s=100,c='blue', label='Cluster2')
plt.scatter(X[y_kmeans == 2,0],X[y_kmeans == 2,1],s=100,c='green',label='Cluster3')
plt.scatter(X[y_kmeans == 3,0],X[y_kmeans == 3,1],s=100, c ='cyan',label = 'CLuster4')
plt.scatter(X[y_kmeans == 4, 0], X[y_kmeans == 4, 1], s = 100, c = 'magenta', label = 'Cluster 5')
plt.scatter(kmeans.cluster_centers_[:,0],kmeans.cluster_centers_[:,1],s=300, c = 'yellow', label ='Centroids')
plt.title('Clusters of customers')
plt.xlabel('Annual Income (k$)')
plt.ylabel('Spending Score (1-100)')
plt.legend()
plt.show()
I have added the output image for reference purpose
elbow graph,
Final cluster image

That's a filter. y_kmeans == 0 selects those elements where y_kmeans[i] is equal to 0. X[y_kmeans == 0, 0] selects the elements of X where the corresponding y_kmeans value is 0 and the second dimension is 0.
Originally answered by tim roberts
X[y_hc ==1,0] here 0 means model is in x plain X[y_hc == 0,1] means model is in y-plain.
Where as 1 refers to the value of [i] or the cluster value.

X[y_kmeans == 0, 0] :
It's a filter that works like a slicing strategy (X[start_rows : end_rows , selected column]). it's like you are selecting samples from your dataset X from a given row number to a specific given row number and after selecting these rows, only use column 0. This will work perfectly if our samples were contiguous unfortunately it is not since we want to select rows based on the cluster made by our model which is contained in y.
Explication below:
Remember y contains the result of your clustering model where we have 5 clusters represented as cluster 0, cluster 1 ... cluster 4.
At first y_kmeans == 0 will select the elements where y==0, meaning elements classified as cluster 0 so y==0 return a list of boolean with True for those elements belonging to cluster 0 and false for other elements. The outcome will now be X[[True, False, etc...],0], the first element in the bracket represents the list of boolean mentioned above and the second element ( the 0 ) represents the column (or feature. Example sepal length for the Iris dataset). Also, remember to make a scatter plot we need two values (x and y) in the case of the iris dataset, X can be the Sepal length and Y the Sepal Width.
So the first line
X[y_kmeans == 0,0],X[y_kmeans == 0,1]
will be evaluated to X[[True, False...],0] and X[[True, False],1] the bolded value here represents the column's value in your original dataset. Each Boolean value is mapped to the corresponding row in your dataset, if the value is True, that row is selected and its columns value (corresponding to the bolded part of the bracket) is selected. So you will have something like this:
x[[False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, True, True, False, True,
True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True, True, True, True, False, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, False, True, False, False, False, False, True, False,
False, False, False, False, False, True, True, False, False,
False, False, True, False, True, False, True, False, False,
True, True, False, False, False, False, False, True, False,
False, False, False, True, False, False, False, True, False,
False, False, True, False, False, True],0]
Note that the number of rows in your dataset or X must be equal to the number of elements in your y.

Related

get texts from array at indexes where 2D tensor's values are above or equal to thresholds in tensorflow2

I have tensorflow tensor with probabilites like this:
>>> valid_4_preds
array([[0.9817431 , 0.01259811, 0.50729334, 0.00053732, 0.6966804 ,
0.00488825],
[0.9851129 , 0.01246135, 0.38177294, 0.00378728, 0.8398497 ,
0.68413687],
[0.00061161, 0.00005008, 0.00017785, 0.0000152 , 0.00017121,
0.00002404],
[0.9991425 , 0.23962161, 0.98579687, 0.01727398, 0.9354003 ,
0.3325037 ]], dtype=float32)
I now need to map the above probabilties with different thresholds to classes(or a tensor with texts) and get them.
>>> # printing classes
>>> classes
<tf.Tensor: shape=(6,), dtype=string, numpy=
array([b'class_1', b'class_2', b'class_3', b'class_4', b'class_5',
b'class_6'], dtype=object)>
>>> # converting to bools
>>> true_falses = tf.math.greater_equal(valid_4_preds, tf.constant([0.5, 0.40, 0.20, 0.80, 0.5, 0.4]))
>>> true_falses
<tf.Tensor: shape=(4, 6), dtype=bool, numpy=
array([[ True, False, True, False, True, False],
[ True, False, True, False, True, True],
[False, False, False, False, False, False],
[ True, False, True, False, True, False]])>
now, I am trying to get the texts at indices where true_falses has Trues(this is my expected output), like this:
>>> <some-tensorflow-operations>
<tf.Tensor: shape=(4, 6), dtype=bool, numpy=
array([['class_1', 'class_3', 'class_5'],
['class_1', 'class_3', 'class_5', 'class_6'],
[],
['class_1', 'class_3', 'class_5']])>
Here's what I have tried:
tf.boolean_mask seems to solve the purpose, but the mask it takes in, strictly has to be 1D array.
tf.where can be used to get the indexes, output of which after reshaping to single dimension can be passed to tf.gather to get the respective classes like this:
>>> tf.gather(classes, tf.reshape(tf.where(true_falses[0] == True), shape=(-1,)))
<tf.Tensor: shape=(3,), dtype=string, numpy=array([b'class_1', b'class_3', b'class_5'], dtype=object)>
But, I haven't been able to figure out how to do this on 2D arrays.
this logic will go in a signature for serving via tensorflow-serving, so operations strictly only needs to be of tensorflow. How do I do this on 2D tensors or arrays? more efficient and quicker operations would be appreciated.
tf.ragged.boolean_mask?
import tensorflow as tf
classes = tf.constant([b'class_1', b'class_2', b'class_3', b'class_4', b'class_5', b'class_6'])
true_falses = tf.constant([
[ True, False, True, False, True, False],
[ True, False, True, False, True, True],
[False, False, False, False, False, False],
[ True, False, True, False, True, False]]
)
tf.ragged.boolean_mask(
data=tf.tile(tf.expand_dims(classes, 0), [tf.shape(true_falses)[0], 1]),
mask=true_falses
)
# <tf.RaggedTensor [[b'class_1', b'class_3', b'class_5'], [b'class_1', b'class_3', b'class_5', b'class_6'], [], [b'class_1', b'class_3', b'class_5']]>

A question about pytorch change tensor shape

When I want to split an image into multiple patches, the first thing I thought was using pytorch view() function. For example, An image of shape (1,3,256,256)(pytorch style), and split it into 8x8=64 patches, each patch height and width is 32. So for this image, we can get 256/32=8 for row and 8 for column patches, so we total have 8x8=64 patches.
I want to split the image (1,3,256,256) into patches, each patch shape is (1,3,32,32), and reshape these tensor into shape of (1,8x8,32x32x3), here 8x8 is the number of patches, 32x32x3 is patch height * width * channel.
Code below use einops rearrange function can get the correct answer, but when I use view function, I got correct shape but incorrect value tensor. Who can tell me how to implement this operation by view function?
from einops.layers.torch import Rearrange
img = torch.randn(1, 3, 256, 256)
import copy
img2 = copy.deepcopy(img)
b, c, h, w = img.size()
p=32
to_patch_embedding = nn.Sequential(
Rearrange('b c (h p1) (w p2) -> b (h w) (p1 p2 c)', p1=32, p2=32),
)
img2 = img2.view(b, h // p * w // p, c * p * p)
print(img2.shape)
print(img2==to_patch_embedding(img))
----------------------------------------output--------------------------------------------
torch.Size([1, 64, 3072])
tensor([[[ True, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, True]]])
You can try this way as mentioned on pytorch discuss.
import torch
a = torch.randn(1, 3, 256, 256)
a = a.unfold(2, 32, 32).unfold(3, 32, 32)
a = a.contiguous().view(a.size(0), a.size(2)*a.size(3), a.size(1)*a.size(-1)*a.size(-2))
print(a.shape)
The output shape is as you expected:
torch.Size([1, 64, 3072])
Hope this is useful to you.

Python numpy boolean array not whole columns and rows

I want to apply the NOT operation on whole columns/rows of a boolean Numpy array. Is this possible with Numpy?
matrix = np.array([[False for i in range(3)] for j in range(2)])
# Initial
# [False, False, False]
# [False, False, False]
matrix[:,1].not() # Something like this
# After not operation on column 1
# [False, True, False]
# [False, True, False]
This should do the trick, see here
matrix[:, 1] = np.logical_not(matrix[:, 1])

How to do numpy logical_and with a margin?

I have two numpy vector arrays, one contains binary values so either 1 or 0 and the other float values so anything in between 0 and 1.
I want to use the numpy.logical_and operator and have it return true if the binary value is in the range of the float plus or minus 0.2. So i.e. a float of 0.1 would return true, 0.4 false.
How would I tackle this?
I think what you want is np.isclose. In this case implementation would be:
bin_arr = np.random.randint(2, size = 100)
float_arr = np.random.rand(100)
out = np.isclose(bin_arr.astype(float), float_arr, atol = .2)
Note that while logical_and is a ufunc (Universal Function) with extended functionality, np.isclose is not.
Does the question require True if (float_arr less than 0.2) AND (bin_arr > 0). Which does need the use of logical and.
Or True if abs(float_arr - bin_arr) <= 0.2 which doesn't. #Daniel F 's use of isclose() is an elegant answer to this.
# Set up some data
np.random.seed(0) # Make it repeatable.
bin_arr = np.random.randint(2, size = 20)
float_arr = np.random.rand(20)
bin_arr, float_arr
# (array([0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1]),
# array([0.79172504, 0.52889492, 0.56804456, 0.92559664, 0.07103606,
# 0.0871293 , 0.0202184 , 0.83261985, 0.77815675, 0.87001215,
# 0.97861834, 0.79915856, 0.46147936, 0.78052918, 0.11827443,
# 0.63992102, 0.14335329, 0.94466892, 0.52184832, 0.41466194]))
True if (float_arr less than 0.2) AND (bin_arr > 0)`.
np.logical_and( float_arr<=0.2, bin_arr)
# array([False, False, False, False, True, True, True, False, False,
# False, False, False, False, False, False, False, False, False,
# False, False])
True if abs(float_arr - bin_arr) <= 0.2
np.abs(float_arr - bin_arr)<=0.2
# array([False, False, False, False, False, False, False, True, False,
# True, True, False, False, False, True, False, True, False,
# False, False])

Get path of boundaries of contiguous regions in 2D array

Say I have an array like this:
import numpy as np
arr = np.array([
[1, 1, 3, 3, 1],
[1, 3, 3, 1, 1],
[4, 4, 3, 1, 1],
[4, 4, 1, 1, 1]
])
There are 4 distinct regions: The top left 1s, 3s, 4s and right 1s.
How would I get the paths for the bounds of each region? The coordinates of the vertices of the region, in order.
For example, for the top left 1s, it is (0, 0), (0, 2), (1, 2), (1, 1), (2, 1), (2, 0)
(I ultimately want to end up with something like start at 0, 0. Right 2. Down 1. Right -1. Down 1. Right -1. Down -2., but it's easy to convert, as it's just the difference between adjacent vertices)
I can split it up into regions with scipy.ndimage.label:
from scipy.ndimage import label
regions = {}
# region_value is the number in the region
for region_value in np.unique(arr):
labeled, n_regions = label(arr == region_value)
regions[region_value] = [labeled == i for i in range(1, n_regions + 1)]
Which looks more like this:
{1: [
array([
[ True, True, False, False, False],
[ True, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False]
], dtype=bool), # Top left 1s region
array([
[False, False, False, False, True],
[False, False, False, True, True],
[False, False, False, True, True],
[False, False, True, True, True]
], dtype=bool) # Right 1s region
],
3: [
array([
[False, False, True, True, False],
[False, True, True, False, False],
[False, False, True, False, False],
[False, False, False, False, False]
], dtype=bool) # 3s region
],
4: [
array([
[False, False, False, False, False],
[False, False, False, False, False],
[ True, True, False, False, False],
[ True, True, False, False, False]
], dtype=bool) # 4s region
]
}
So how would I convert that into a path?
a pseudo code idea would be to do the following:
scan multi-dim array horizontally and then vertically until you find True value (for second array it is (0,4))
output that as a start coord
since you have been scanning as determined above your first move will be to go right.
repeat until you come back:
move one block in the direction you are facing.
you are now at coord x,y
check values of ul=(x-1, y-1), ur=(x-1, y), ll=(x, y-1), lr=(x,y)
# if any of above is out of bounds, set it as False
if ul is the only True:
if previous move right:
next move is up
else:
next move is left
output previous move
move by one
..similarly for other single True cells..
elif ul and ur only True or ul and ll only True or ll and lr only True or ur and lr only True:
repeat previous move
elif ul and lr only True:
if previous move left:
next move down
elif previous move right:
next move up
elif preivous move down:
next move left:
else:
next move right
output previous move
move one
elif ul, ur, ll only Trues:
if previous move left:
next move down
else:
next move right
output previous move, move by one
...similarly for other 3 True combos...
for the second array it will do the following:
finds True val at 0,4
start at 0,4
only lower-right cell is True, so moves right to 0,5 (previous move is None, so no output)
now only lower-left cell is True, so moves down to 1,5 (previous move right 1 is output)
now both left cells are True, so repeat move (moves down to 2,5)
..repeat until hit 4,5..
only upper-left cell is True, so move left (output down 4)
both upper cells are true, repeat move (move left to 3,4)
both upper cells are true, repeat move (move left to 2,4)
upper right cell only true, so move up (output right -3)
..keep going until back at 0,4..
Try visualising all the possible coord neighbouring cell combos and that will give you a visual idea of the possible flows.
Also note that with this method it should be impossible to be traversing a coord which has all 4 neighbours as False.

Categories

Resources