#python #syntax #statistics #sklearn-pandas
Вопрос:
Добрый вечер,
В настоящее время я получаю докторскую степень по химии, и в этой структуре я пытаюсь применить свои немногочисленные знания в области python и статистики, чтобы различать образцы на основе их ИК-спектра. После нескольких недель сбора данных я, наконец, смог собрать свой набор данных и собирался посмотреть, что может предложить PCA (это была самая простая часть).
Я смог создать свой сценарий и получить нагрузки, оценки и все остальное, что мне могло понадобиться или чего я хотел. Однако я использовал стандартный масштабер из sklearn.предварительная обработка для уменьшения масштаба моих данных, поэтому (исправьте меня, если я ошибаюсь) Я должен вернуть нагрузки в это «стандартное масштабированное» пространство.
Поскольку мои данные являются реальными ИК-спектрами, эти нагрузки имеют химическое значение (даже если предположить, что реального спектра нет), например, если мои нагрузки PC1 имеют пик при XX см-1, я знаю, что образцы с высоким содержанием PC1, вероятно, содержат соединения, которые поглощают при этом волновом числе . Поэтому я хочу отменить преобразование стандартного масштабирования. Я пытался использовать StandardScaler.inverse_transform (), однако, похоже, он возвращает мне тот же массив, который я ему дал… что очень расстраивает… Я пытаюсь сделать то же самое со своими образцами спектра, но это снова дало мне тот же результат : вот часть моего сценария, где я попробовал это :
Wavenumbers = DFF.columns
#in fact this is a little more complicated but that's the spirit
Spectre = DFF.values.tolist()
#btw DFF is my pandas.dataframe containing spectrum with features = wavenumber
SS = StandardScaler(copy=True)
DFF = SS.fit_transform(DFF) #at this point I use SS for preprocessing before PCA
#I'm then trying to inverse SS and get back the 1rst spectrum of the dataset
D = SS.inverse_transform(DFF[0])
#However at this point DFF[0] and D are almost-exactly the same I'm sure because :
plt.plot(Wavenumbers,D)
plt.plot(Wavenumbers,DFF[0]) #the curves are the sames, and :
for i,j in enumerate(D) :
if j==DFF[0][i] : pass
else : print("{}".format(j-DFF[0][i] )) #return nothing bigger than 10e-16
Проблема, скорее всего, в синтаксисе или в том, как я использовал StandardScaler, однако вокруг меня нет никого, кто мог бы обратиться за помощью в этом . Кто-нибудь может сказать мне, что я сделал не так ? или дайте мне подсказку о том, как я мог бы вернуть свои нагрузки в пространство «реальных ИК-спектров»?
PS: извините за дурацкий английский, и я надеюсь, что это будет понятно
Комментарии:
1. Я не знаю, стоит ли беспокоиться о том, чтобы разобраться в том, что происходит со Стандартскейлером или чем-то еще. PCA концептуально прост, так почему бы просто не сделать это вручную. Заставить StandardScaler делать то, что вы хотите, не может быть проще, чем просто сделать это самостоятельно.
2. Спасибо, но вы знаете, что ИК-спектры на самом деле довольно большие, и выполнение PCA вручную, как вы предлагаете, кажется огромной тратой времени. Я собираюсь создать свой собственный стандартскейлер (что не так уж сложно), но перед этим я хотел быть уверенным, что не совершил глупой ошибки. Кроме того, я не технарь, поэтому, если могу, предпочитаю использовать встроенную библиотеку вместо самодельной функции.
3. и кстати, StandardScaler предназначен для того, чтобы делать именно то, что я хочу делать. Отсюда мое отчаяние, когда я не могу заставить это работать
Ответ №1:
Добрый вечер,
Отложив проблему на несколько дней, я, наконец, перекодировал нужную мне функцию (как предложил Роберт Додье).
Для напоминания я хотел иметь функцию, которая могла бы извлекать мои данные из фрейма данных pandas и центрировать их по среднему значению для выполнения PCA, но также могла бы отменить предварительную обработку для последних применений.
Вот код, который я получил в итоге :
import pandas as pd
import numpy as np
class Scaler:
std =[]
mean = []
def fit(self,DF):
self.std=[]
self.mean=[]
for c in DF.columns:
self.std.append(DF[c].std())
self.mean.append(DF[c].mean())
def transform(self,DF):
X = np.zeros(shape=DF.shape)
for i,c in enumerate(DF.columns):
for j in range(len(DF.index)):
X[j][i] = (DF[c][j] - self.mean[i]) / self.std[i]
return X
def reverse(self,X):
Y = np.zeros(shape=X.shape)
for i in range(len(X[0])):
for j in range(len(X)):
Y[j][i] = X[j][i] * self.std[i] self.mean[i]
return Y
def fit_transform(self,DF):
self.fit(DF)
X = self.transform(DF)
return X
Он довольно медленный и, безусловно, очень низкотехнологичный, но, похоже, справляется с работой просто отлично. Надеюсь, это сэкономит некоторое время другим новичкам в python.
Я разработал его так, чтобы он был максимально близок к sklearn.предварительная обработка.Это делает стандартскейлер.
пример :
S = Scaler() #create scaler object
S.fit(DF) #fit the scaler to the dataframe (calculate mean and std for every columns in DF /! DF must be a pd.dataframe)
X=S.transform(DF) # return a np.array with mean centered data
Y = S.reverse(X) # reverse the transformation to get back original data
Еще раз извините за быстрый английский. И спасибо Роберту за то, что нашел время ответить.