Map test data using sklearn TSNE - python

Is there a way to extract the mapping procedure in sklearn.manifold.TSNE in python so that you can map new data into the reduced dimensional space?
Importantly, I mean without having to retrain on the new data as well here.
For example say you trained a TSNE map as follows:
import numpy as np
from sklearn.manifold import TSNE
X = np.array([[0, 0, 0], [0, 1, 1], [1, 0, 1], [1, 1, 1]])
X_embedded = TSNE(n_components=2).fit_transform(X)
As seen in the documentation: https://scikit-learn.org/stable/modules/generated/sklearn.manifold.TSNE.html
Can you extract the transformation so that you can map new data into the same space:
Y = np.array([[0, 0.8, 0.8], [0.1, 0, 1], [1.2, 0.2, 1], [1, 1.1, 1]])
Any help on this matter would be greatly appreciated!

tSNE is a non-linear, non-parametric embedding.
So there is no "closed form" way of updating it with new points. Even worse: adding new points may require existing points to move.
Because of this, making tSNE apply to new data will require substantial changes to the method, it won't be the original tSNE anymore.

Parametric t-SNE has option to apply on the test data but this is not available in Sklearn. Reference issue.
Having set this we have mention that it is implemented in other place here

Related

What is the difference between fit() and fit_predict() in SpectralClustering

I am trying to understand and use the spectral clustering from sklearn.
Let us say we have X matrix input and we create a spectral clustering object as follows:
clustering = SpectralClustering(n_clusters=2,
assign_labels="discretize",
random_state=0)
Then, we call a fit_predict using the spectral cluster object.
clusters = clustering.fit_predict(X)
What confuses me is that when does 'the affinity matrix for X using the selected affinity is created'? Because as per the documentation the
fit_predict() method 'Performs clustering on X and returns cluster labels.' But it doesn't explicitly say that it also computes 'the affinity matrix for X using the selected affinity' before clustering.
I appreciate any help or tips.
As already implied in another answer, fit_predict is just a convenience method in order to return the cluster labels. According to the documentation, fit
Creates an affinity matrix for X using the selected affinity, then applies spectral clustering to this affinity matrix.
while fit_predict
Performs clustering on X and returns cluster labels.
Here, Performs clustering on X should be understood as what is described for fit, i.e. Creates an affinity matrix [...].
It is not difficult to verify that calling fit_predict is equivalent to getting the labels_ attribute from the object after fit; using some dummy data, we have
from sklearn.cluster import SpectralClustering
import numpy as np
X = np.array([[1, 2], [1, 4], [10, 0],
[10, 2], [10, 4], [1, 0]])
# 1st way - use fit and get the labels_
clustering = SpectralClustering(n_clusters=2,
assign_labels="discretize",
random_state=0)
clustering.fit(X)
clustering.labels_
# array([1, 1, 0, 0, 0, 1])
# 2nd way - using fit_predict
clustering2 = SpectralClustering(n_clusters=2,
assign_labels="discretize",
random_state=0)
clustering2.fit_predict(X)
# array([1, 1, 0, 0, 0, 1])
np.array_equal(clustering.labels_, clustering2.fit_predict(X))
# True
Looking at source code of fit_predict() it seems that it's just a convenience method - it literally just calls fit() and returns labels from the object.

fit_transform data before running algorithm

The preprocessing module further provides a utility class
StandardScaler that implements the Transformer API to compute the mean
and standard deviation on a training set so as to be able to later
reapply the same transformation on the testing set.
http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html#sklearn.preprocessing.StandardScaler.fit_transform
When transforming the dataset you run an algorithm on, how do you link the results back to the original dataset?
E.g.
data = [[0, 0], [0, 0], [1, 1], [1, 1]]
print(data);
-->[[0, 0], [0, 0], [1, 1], [1, 1]]
myData = StandardScaler().fit_transform(data)
print(myData);
-->[[-1. -1.]
[-1. -1.]
[ 1. 1.]
[ 1. 1.]]
When running an algorithm on myData (unsupervised), how can you interpret results on that dataset when it's changed before running? E.g. when you run a clustering algorithm on myData, you are not clustering the original data.
Apply the inverse_transform to get back to the original data:
from sklearn.preprocessing import StandardScaler
import numpy as np
data = [[0, 0], [0, 1], [1, 0], [1, 1]]
scaler = StandardScaler()
myData = scaler.fit_transform(data)
restored = scaler.inverse_transform(myData)
assert np.allclose(restored, data) # check we got the original data back
Note how an instance of StandardScaler is stored in a variable for later use. After fitting, this instance contains all the information required to repeat or undo the transformation.
Now, if you performed clustering on myData you can pass the cluster prototypes (centers, or whatever you get from the clustering algorithm) to scaler.inverse_transform to get the clusters in the original data space.

Scipy and Sklearn chi2 implementations give different results

I an using sklearn.feature_selection.chi2 for feature selection and found out some unexpected results (check the code). Do anyone knows what is the reason or can point me to some documentation or pull request?
I include a comparison of the results I got and the expected ones obtained by hand and using scipy.stats.chi2_contingency.
The code:
import numpy as np
import pandas as pd
from scipy.stats import chi2_contingency
from sklearn.feature_selection import chi2, SelectKBest
x = np.array([[1, 1, 1, 0, 1], [1, 0, 1, 0, 0], [0, 0, 1, 1, 1], [0, 0, 1, 1, 0], [0, 0, 0, 1, 1], [0, 0, 0, 1, 0]])
y = np.array([1, 1, 2, 2, 3, 3])
scores = []
for i in range(x.shape[1]):
result = chi2_contingency(pd.crosstab(x[:, i], y))
scores.append(result[0])
sel = SelectKBest(score_func=chi2, k=3)
sel.fit(x, y)
print(scores)
print(sel.scores_)
print(sel.get_support())
The results are:
[6., 2.4, 6.0, 6.0, 0.0] (Expected)
[4. 2. 2. 2. 0.] (Unexpected)
[ True True False True False]
Using scipy, it keeps features 0, 2, 3, while, with sklearn it keeps features 0,1,3.
First, you have the observed values and expected values interchanges when calculating with the scipy implementation, it should be
scores = []
for i in range(x.shape[1]):
result = chi2_contingency(pd.crosstab(y,x[:,i] ))
scores.append(result[0])
So now the scipy results are :
[6.000000000000001, 2.4000000000000004, 6.000000000000001, 6.000000000000001, 0.0]
While the one with sklearn's chi2 are
[4. 2. 2. 2. 0.]
Now I went into the source code, and they both calculate the chi square values little differently
The sklearn implementation
You can check line 171 where chi2 class is defined, this the implementation in sklearn before being passed to _chisquare class.
scipy implementation
You can view the scipy implementation here,which calls this function to finally calculate the chi square values.
As you can see from the implementation the difference in values is because of the transformations they perform on the obsevred and expected values before calculating the chi square values.
References:
chi square feature selection using scipy
Yes, they do give different results. And I think you should trust the results from scipy, and reject the results from sklearn.
But let me provide details of my reasoning, because I could be wrong.
I lately observed a similar effect to what you describe, with a data set of 300 data points: the results of the two chi2 implementations differ indeed. In my case the difference was striking. I described the issue in details in this article , followed by this Cross Validated discussion thread and I also submitted a bug request to sklearn, available for review here.
The added value from my research, if any, seems to be that the results delivered by the scipy implementation seem correct, while the results from sklearn are incorrect. Please see the article for the details. But I only focused on my sample, so the conclusion may not be universally true. Sadly the source code analysis is beyond my capability, but I hope this input can help someone to possibly either improve the code, or disprove my reasoning if wrong.

warning message in scikit-learn [duplicate]

This question already has answers here:
Preprocessing in scikit learn - single sample - Depreciation warning
(8 answers)
Closed 5 years ago.
I wrote a very simple scikit-learn decision tree to implement XOR:
from sklearn import tree
X = [[0, 0], [1, 1], [0, 1], [1, 0]]
Y = [0, 0, 1, 1]
clf = tree.DecisionTreeClassifier()
clf = clf.fit(X, Y)
print(clf.predict([0,1]))
print(clf.predict([0,0]))
print(clf.predict([1,1]))
print(clf.predict([1,0]))
predict part generates some warning like this:
DeprecationWarning: Passing 1d arrays as data is deprecated in 0.17
and will raise ValueError in 0.19. Reshape your data either using
X.reshape(-1, 1) if your data has a single feature or X.reshape(1, -1)
if it contains a single sample.
I don't have a clear idea what needs to change and why? Please enlighten me!
Thank you in advance!
The input to clf.predict should be a 2D array. Thus, instead of writing
print(clf.predict([0,1]))
you need to write
print(clf.predict([[0,1]]))
The method operates on matrices (2D arrays), rather than vectors (1D arrays). As a convenience, the older code accepted a vector as a 1xN matrix. This led to usage errors as some users forgot which way a vector was oriented (1xN vs Nx1).
The suggestion tells you how to reshape your vector to the proper matrix shape. For constant vectors, just write them as matrices:
clf.predict( [ [0, 1] ] )
The "other direction" (wrong for this application) would be
clf.predict( [ [0], [1] ] )
As the warning message pointed out, you have single sample to test. Thus you could use reshape or fix as followings,
from sklearn import tree
X = [[0, 0], [1, 1], [0, 1], [1, 0]]
Y = [0, 0, 1, 1]
clf = tree.DecisionTreeClassifier()
clf = clf.fit(X, Y)
print (clf.predict([[0,1]]))
print (clf.predict([[0,0]]))
print (clf.predict([[1,1]]))
print (clf.predict([[1,0]]))

Adding new points to the t-SNE model

I try to use t-SNE algorithm in the scikit-learn:
import numpy as np
from sklearn.manifold import TSNE
X = np.array([[0, 0, 0], [0, 1, 1], [1, 0, 1], [1, 1, 1]])
model = TSNE(n_components=2, random_state=0)
np.set_printoptions(suppress=True)
model.fit_transform(X)
Output:
array([[ 0.00017599, 0.00003993], #1
[ 0.00009891, 0.00021913],
[ 0.00018554, -0.00009357],
[ 0.00009528, -0.00001407]]) #2
After that I try to add some points with the coordinates exactly like in the first array X to the existing model:
Y = np.array([[0, 0, 0], [1, 1, 1]])
model.fit_transform(Y)
Output:
array([[ 0.00017882, 0.00004002], #1
[ 0.00009546, 0.00022409]]) #2
But coords in the second array not equal to the first and last coords from the first array.
I understand that this is the right behaviour, but how can I add new coords to the model and get the same coords in the output array for the same coords in the input array?
Also I still need to get closest points even after appending new points.
Quoting the author of t-SNE from here: https://lvdmaaten.github.io/tsne/
Once I have a t-SNE map, how can I embed incoming test points in that map?
t-SNE learns a non-parametric mapping, which means that it does not learn an explicit function that maps data from the input space to the map. Therefore, it is not possible to embed test points in an existing map (although you could re-run t-SNE on the full dataset). A potential approach to deal with this would be to train a multivariate regressor to predict the map location from the input data. Alternatively, you could also make such a regressor minimize the t-SNE loss directly, which is what I did in this paper.
Also, this answer on stats.stackexchange.com contains ideas and a link to
a very nice and very fast recent Python implementation of t-SNE https://github.com/pavlin-policar/openTSNE that allows embedding of new points out of the box
and a link to https://github.com/berenslab/rna-seq-tsne/.

Categories

Resources