标准化熊猫数据框的列


226

我在熊猫中有一个数据框,其中每一列都有不同的值范围。例如:

df:

A     B   C
1000  10  0.5
765   5   0.35
800   7   0.09

知道如何将每个值介于0和1之间的数据框的列标准化吗?

我想要的输出是:

A     B    C
1     1    1
0.765 0.5  0.7
0.8   0.7  0.18(which is 0.09/0.5)

1
有一个应用函数,例如frame.apply(f,axis = 1),其中f是一个对行执行某些操作的函数...
tschm 2014年

1
规范化可能不是最合适的措辞,因为scikit-learn文档将其定义为“将单个样本缩放为具有单位范数的过程 ”(即,如果我正确理解的话,逐行)。
Skippy le Grand Gourou

我不明白,为什么将min_max缩放视为标准化!正常已得到了在均值为零,方差为1的正态分布的意义意思
溢出警方

如果您在2020年或之后访问此问题,请查看@Poudel的答案,如果使用pandas vs sklearn,您将获得不同的归一化答案。
Bhishan Poudel

@Poudel是由于ddof争论吗?
fffrost

Answers:


223

您可以使用软件包sklearn及其关联的预处理实用程序来规范化数据。

import pandas as pd
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 = pd.DataFrame(x_scaled)

有关更多信息,请参见有关预处理数据的scikit-learn 文档:将特征缩放到一定范围。


46
我认为这将摆脱列名,这可能是op首先使用数据帧的原因之一。
pietz

47
除非先转置,否则这将标准化行而不是列。做Q要求的事情:pd.DataFrame(min_max_scaler.fit_transform(df.T), columns=df.columns, index=df.index)
炉灶

26
@pietz保留列名,请参阅这篇文章。基本上将最后一行替换为,df=pandas.DataFrame(x_scaled, columns=df.columns)
ijoseph

5
@hobs这是不正确的。桑德曼(Sandman)的代码规范了按列和按列的规范。如果转置,将得到错误的结果。
petezurich

8
@petezurich看来Sandman或Praveen更正了他们的代码。不幸的是,不可能纠正评论;)
滚刀

397

使用Pandas的一种简单方法:(这里我要使用均值归一化)

normalized_df=(df-df.mean())/df.std()

使用最小-最大规格化:

normalized_df=(df-df.min())/(df.max()-df.min())

编辑:要解决一些问题,需要说熊猫自动在上面的代码中应用了以列为单位的函数。


16
我喜欢这一个。它简短,表达力强,并保留标题信息。但我认为您也需要减去分母中的最小值。
pietz

6
我不认为这是错的。对我来说效果很好-我认为mean()和std()不需要返回数据帧即可正常工作,并且您的错误消息并不表示它们不是数据帧是一个问题。
Strandtasche

24
这不是按列标准化。这将整个矩阵归一化,这将提供错误的结果。
Nguai al

6
也为我工作得很漂亮。@Nguaial您可能会在numpy矩阵上尝试此操作,在这种情况下,结果将是您所说的。但对于Pandas数据框,默认情况下,min,max,...度量按列应用。
辅助

1
我也喜欢这个
Isaac Sim,

51

根据这篇文章:https : //stats.stackexchange.com/questions/70801/how-to-normalize-data-to-0-1-range

您可以执行以下操作:

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

您无需担心您的价值观是消极还是积极。并且这些值应在0到1之间很好地分布。


8
当最小值和最大值相同时要小心,您的分母为0,您将获得NaN值。
Hrushikesh Dhumal

36

您的问题实际上是作用在列上的简单转换:

def f(s):
    return s/s.max()

frame.apply(f, axis=0)

或更简洁:

   frame.apply(lambda x: x/x.max(), axis=0)

2
lambda一个是最好的:-)
阿布Shoeb

4
因为问题是按列标准化,这不应该是axis = 1吗?
Nguai al

不,从文档axis [...] 0 or 'index': apply function to each column。默认值实际上是axis=0这样,因此可以写得更短:-)谢谢@tschm。
jorijnsmit

30

如果您喜欢使用sklearn包,则可以通过使用pandas来保留列名和索引名,loc如下所示:

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler() 
scaled_values = scaler.fit_transform(df) 
df.loc[:,:] = scaled_values

27

简单即美:

df["A"] = df["A"] / df["A"].max()
df["B"] = df["B"] / df["B"].max()
df["C"] = df["C"] / df["C"].max()

太好了,我认为这是最好的解决方案!
Maciej A. Bednarz '18

6
请注意,OP要求[0..1]范围,此解决方案扩展到[-1..1]范围。尝试使用数组[-10,10]。
亚历山大·索斯诺夫申科

3
@AlexanderSosnovshchenko不是真的。罗勒·穆萨(Basil Musa)假设OP的矩阵始终为非负数,这就是他给出此解决方案的原因。如果某列的条目为负,则此代码不会归一化为[-1,1]范围。尝试使用数组[-5,10]。Cina的答案给出了使用负值归一化为[0,1]的正确方法df["A"] = (df["A"]-df["A"].min()) / (df["A"].max()-df["A"].min())
facuq

简单明了
joshi123 '18

也许甚至更简单:df /= df.max()-假设目标是分别标准化每个列。
n1k31t4

24

您可以创建要标准化的列的列表

column_names_to_normalize = ['A', 'E', 'G', 'sadasdsd', 'lol']
x = df[column_names_to_normalize].values
x_scaled = min_max_scaler.fit_transform(x)
df_temp = pd.DataFrame(x_scaled, columns=column_names_to_normalize, index = df.index)
df[column_names_to_normalize] = df_temp

现在,您的Pandas Dataframe仅在您想要的列上进行了标准化


但是,如果你想的相反,选择列的列表不要想规范化,您可以简单地创建的所有列的列表,删除非期望的人

column_names_to_not_normalize = ['B', 'J', 'K']
column_names_to_normalize = [x for x in list(df) if x not in column_names_to_not_normalize ]

11

我认为在熊猫中做到这一点的更好方法是

df = df/df.max().astype(np.float64)

编辑如果在数据框中出现负数,则应改用

df = df/df.loc[df.abs().idxmax()].astype(np.float64)

1
如果一列的所有值都为零,则将不起作用
ahajib

除非最小值为0,否则将当前值除以最大值不会给您正确的归一化
。– pietz

我同意,但这就是旧约要的(见他的例子)
Daniele

11

Sandman和Praveen给出的解决方案非常好。唯一的问题是,如果数据框的其他列中有类别变量,则此方法将需要进行一些调整。

我针对此类问题的解决方案如下:

 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])

2
这个答案很有用,因为互联网上的大多数示例都将一个定标器应用于所有列,而这实际上解决了一个定标器(例如MinMaxScaler)不应应用于所有列的情况。
demongolem

10

python中不同标准化的示例。

作为参考,请参阅以下维基百科文章: https //en.wikipedia.org/wiki/Unbiased_estimation_of_standard_deviation

示例数据

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

使用熊猫进行归一化(给出无偏估计)

归一化时,我们只需减去平均值并除以标准差即可。

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

使用sklearn进行归一化(Gives有偏差的估计,与熊猫不同)

如果您做同样的事情,sklearn您将获得不同的输出!

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

偏向sklearn的估计是否会使机器学习功能降低?

没有。

sklearn.preprocessing.scale的官方文档指出,使用偏倚估计量会异常地影响机器学习算法的性能,因此我们可以安全地使用它们。

From official documentation:
We use a biased estimator for the standard deviation,
equivalent to numpy.std(x, ddof=0). 
Note that the choice of ddof is unlikely to affect model performance.

MinMax Scaling怎么样?

MinMax缩放中没有标准偏差计算。因此,在熊猫和scikit-learn中,结果都是相同的。

import pandas as pd
df = pd.DataFrame({
               'A':[1,2,3],
               'B':[100,300,500],
             })
(df - df.min()) / (df.max() - df.min())
     A    B
0  0.0  0.0
1  0.5  0.5
2  1.0  1.0


# Using sklearn
from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler() 
arr_scaled = scaler.fit_transform(df) 

print(arr_scaled)
[[0.  0. ]
 [0.5 0.5]
 [1.  1. ]]

df_scaled = pd.DataFrame(arr_scaled, columns=df.columns,index=df.index)
print(df_scaled)
     A    B
0  0.0  0.0
1  0.5  0.5
2  1.0  1.0

6

您可能希望对某些列进行规范化,而对其他列进行不变,例如某些回归任务,其中数据标签或分类列不变,因此,我建议您使用这种pythonic方式(这是@shg和@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()))

5

这只是简单的数学。答案应如下所示。

normed_df = (df - df.min()) / (df.max() - df.min())

2
def normalize(x):
    try:
        x = x/np.linalg.norm(x,ord=1)
        return x
    except :
        raise
data = pd.DataFrame.apply(data,normalize)

从熊猫文件中,DataFrame结构可以对其自身应用操作(函数)。

DataFrame.apply(func, axis=0, broadcast=False, raw=False, reduce=None, args=(), **kwds)

沿DataFrame的输入轴应用功能。传递给函数的对象是Series对象,其索引为DataFrame的索引(axis = 0)或列(axis = 1)。返回类型取决于传递的函数是否聚合,或者取决于DataFrame为空时的reduce参数。

您可以应用自定义函数来操作DataFrame。


2
最好解释一下,为什么您的代码解决了OP的问题,所以人们可以调整策略,而不仅仅是复制您的代码。请阅读我如何写一个好的答案?
T先生

2

以下函数计算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

2

这是使用列表推导按列进行的方式:

[df[col].update((df[col] - df[col].min()) / (df[col].max() - df[col].min())) for col in df.columns]

1

您可以通过这种方式简单地使用pandas.DataFrame.transform 1函数:

df.transform(lambda x: x/x.max())

如果所有值均为负,则此解决方案将不起作用。考虑[-1,-2,-3]。我们除以-1,现在我们得到[1,2,3]。
Dave Liu


0

您可以一行完成

DF_test = DF_test.sub(DF_test.mean(axis=0), axis=1)/DF_test.mean(axis=0)

它对每一列取均值,然后从每一行中减去(均值)(特定列的均值仅从其行中减去)并仅除以均值。最后,我们得到的是标准化数据集。


0

熊猫默认情况下会按列进行规范化。试试下面的代码。

X= pd.read_csv('.\\data.csv')
X = (X-X.min())/(X.max()-X.min())

输出值将在0到1的范围内。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.