J'ai une base de données dans les pandas où chaque colonne a une plage de valeurs différente. Par exemple:
df:
A B C
1000 10 0.5
765 5 0.35
800 7 0.09
Avez-vous une idée de la façon dont je peux normaliser les colonnes de cette image de données où chaque valeur est comprise entre 0 et 1?
Ma sortie souhaitée est:
A B C
1 1 1
0.765 0.5 0.7
0.8 0.7 0.18(which is 0.09/0.5)
Vous pouvez utiliser le package sklearn et ses utilitaires de prétraitement associés pour normaliser les données.
from sklearn import preprocessing
x = df.values #returns a numpy array
min_max_scaler = preprocessing.MinMaxScaler()
x_scaled = min_max_scaler.fit_transform(x)
df = pandas.DataFrame(x_scaled)
Pour plus d'informations, consultez scikit-learn documentation sur le prétraitement des données: mise à l'échelle des fonctionnalités sur une plage.
un moyen facile en utilisant Pandas : (ici je veux utiliser la normalisation moyenne)
normalized_df=(df-df.mean())/df.std()
utiliser la normalisation min-max:
normalized_df=(df-df.min())/(df.max()-df.min())
Basé sur ce post: https://stats.stackexchange.com/questions/70801/how-to-normalize-data-to-0-1-range
Vous pouvez faire ce qui suit:
def normalize(df):
result = df.copy()
for feature_name in df.columns:
max_value = df[feature_name].max()
min_value = df[feature_name].min()
result[feature_name] = (df[feature_name] - min_value) / (max_value - min_value)
return result
Vous n'avez pas besoin de rester inquiet pour savoir si vos valeurs sont négatives ou positives. Et les valeurs doivent être bien réparties entre 0 et 1.
Si vous aimez utiliser le package sklearn, vous pouvez conserver les noms de colonne et d’index en utilisant pandas loc
comme ceci:
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
scaled_values = scaler.fit_transform(df)
df.loc[:,:] = scaled_values
Votre problème est en réalité une simple transformation agissant sur les colonnes:
def f(s):
return s/s.max()
frame.apply(f, axis=0)
Ou même plus laconique:
frame.apply(lambda x: x/x.max(), axis=0)
Le simple est beau:
df["A"] = df["A"] / df["A"].max()
df["B"] = df["B"] / df["B"].max()
df["C"] = df["C"] / df["C"].max()
Je pense qu’un meilleur moyen de le faire chez les pandas est juste
df = df/df.max().astype(np.float64)
Edit Si dans votre bloc de données, des nombres négatifs sont présents, vous devriez utiliser
df = df/df.loc[df.abs().idxmax()].astype(np.float64)
La solution donnée par Sandman et Praveen est très bien. Le seul problème avec cela, si vous avez des variables catégorielles dans d'autres colonnes de votre base de données, cette méthode nécessitera quelques ajustements.
Ma solution à ce type de problème est la suivante:
from sklearn import preprocesing
x = pd.concat([df.Numerical1, df.Numerical2,df.Numerical3])
min_max_scaler = preprocessing.MinMaxScaler()
x_scaled = min_max_scaler.fit_transform(x)
x_new = pd.DataFrame(x_scaled)
df = pd.concat([df.Categoricals,x_new])
Vous voudrez peut-être que certaines colonnes soient normalisées et que d'autres soient inchangées, comme certaines tâches de régression dont les étiquettes de données ou les colonnes catégoriques ne sont pas modifiées. Je vous suggère donc cette méthode pythonique (combinaison des réponses @shg et @Cina):
features_to_normalize = ['A', 'B', 'C']
# could be ['A','B']
df[features_to_normalize] = df[features_to_normalize].apply(lambda x:(x-x.min()) / (x.max()-x.min()))
def normalize(x):
try:
x = x/np.linalg.norm(x,ord=1)
return x
except :
raise
data = pd.DataFrame.apply(data,normalize)
À partir du document de pandas, la structure DataFrame peut s’appliquer à une opération (fonction).
DataFrame.apply(func, axis=0, broadcast=False, raw=False, reduce=None, args=(), **kwds)
Applique une fonction le long de l’axe de saisie de DataFrame . Les objets transmis aux fonctions sont des objets Series ayant pour index l’index de DataFrame (axis = 0) ou les colonnes (axis = 1). Le type de retour dépend de l'agrégation de la fonction transmise ou de l'argument de réduction si le DataFrame est vide.
Vous pouvez appliquer une fonction personnalisée pour utiliser le DataFrame.
Notez que sklearn utilise un estimateur biaisé pour l'écart type. Envisagez de suivre l'exemple suivant:
import pandas as pd
df = pd.DataFrame({
'A':[1,2,3],
'B':[100,300,500],
'C':list('abc')
})
print(df)
A B C
0 1 100 a
1 2 300 b
2 3 500 c
Lors de la normalisation, nous soustrayons simplement la moyenne et divisons par l'écart-type.
df.iloc[:,0:-1] = df.iloc[:,0:-1].apply(lambda x: (x-x.mean())/ x.std(), axis=0)
print(df)
A B C
0 -1.0 -1.0 a
1 0.0 0.0 b
2 1.0 1.0 c
Si vous faites la même chose avec sklearn
vous obtiendrez une sortie DIFFERENTE!
import pandas as pd
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df = pd.DataFrame({
'A':[1,2,3],
'B':[100,300,500],
'C':list('abc')
})
df.iloc[:,0:-1] = scaler.fit_transform(df.iloc[:,0:-1].to_numpy())
print(df)
A B C
0 -1.224745 -1.224745 a
1 0.000000 0.000000 b
2 1.224745 1.224745 c
Les résultats sont différents. Toutefois, conformément à la documentation officielle de sklearn.preprocessing.scale, l’estimateur biaisé est IMPLICABLE d’affecter les performances des algorithmes d’apprentissage automatique et nous pouvons les utiliser en toute sécurité.
Vous pouvez le faire en une seule ligne
DF_test = DF_test.sub(DF_test.mean(axis=0), axis=1)/DF_test.mean(axis=0)
il prend moyenne pour chaque colonne, puis la soustrait (moyenne) de chaque ligne (la moyenne d'une colonne particulière soustrait uniquement de sa ligne) et ne divise que par moyenne. Enfin, nous obtenons l’ensemble de données normalisé.
Ce ne sont que des mathématiques simples. La réponse devrait être aussi simple que ci-dessous.
normed_df = (df - df.min()) / (df.max() - df.min())
Voici comment procéder en colonne en utilisant la compréhension de liste:
[df[col].update((df[col] - df[col].min()) / (df[col].max() - df[col].min())) for col in df.columns]
La fonction suivante calcule le score Z:
def standardization(dataset):
""" Standardization of numeric fields, where all values will have mean of zero
and standard deviation of one. (z-score)
Args:
dataset: A `Pandas.Dataframe`
"""
dtypes = list(Zip(dataset.dtypes.index, map(str, dataset.dtypes)))
# Normalize numeric columns.
for column, dtype in dtypes:
if dtype == 'float32':
dataset[column] -= dataset[column].mean()
dataset[column] /= dataset[column].std()
return dataset