规范化pandas数据帧的列

aha*_*jib 169 python normalize pandas

我在pandas中有一个数据框,其中每列具有不同的值范围.例如:

DF:

A     B   C
1000  10  0.5
765   5   0.35
800   7   0.09
Run Code Online (Sandbox Code Playgroud)

知道如何规范化这个数据帧的列,其中每个值介于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)
Run Code Online (Sandbox Code Playgroud)

Cin*_*ina 296

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

normalized_df=(df-df.mean())/df.std()
Run Code Online (Sandbox Code Playgroud)

使用min-max规范化:

normalized_df=(df-df.min())/(df.max()-df.min())
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这一个.它很简短,它具有表现力,它保留了标题信息.但我认为你需要减去分母中的最小值. (13认同)
  • 这不是按列标准化。这将整个矩阵归一化,这将提供错误的结果。 (10认同)
  • 我不认为这是错的.对我来说很漂亮 - 我不认为mean()和std()需要返回一个数据帧才能使它工作,你的错误信息并不意味着它们不是数据帧是一个问题. (5认同)
  • 如果你想保存一些列 - 执行 `normalized_df['TARGET'] = df['TARGET']` (4认同)
  • 感谢您的评论.我编辑分母. (3认同)
  • 也很适合我。@Nguaial,您可能会在numpy矩阵上尝试此操作,在这种情况下,结果将是您所说的。但是对于Pandas数据框,默认情况下,min,max,...度量按列应用。 (3认同)
  • 是否有一种内置的标准方法可以在每列上执行此操作,而无需循环遍历所有列? (2认同)

San*_*man 165

您可以使用包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)
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请查看有关预处理数据的scikit-learn 文档:将功能扩展到范围.

  • 我认为这将摆脱列名称,这可能是op首先使用数据帧的原因之一. (36认同)
  • 这将规范化行而不是列,除非您先将其转置.要做的Q要求:`pd.DataFrame(min_max_scaler.fit_transform(df.T),columns = df.columns,index = df.index)` (36认同)
  • @pietz保留列名,请参阅[this post](/sf/answers/2093523071/).基本上用`df = pandas.DataFrame(x_scaled,columns = df.columns)替换最后一行 (20认同)
  • @petezurich看起来Sandman或Praveen纠正了他们的代码.不幸的是,无法纠正评论;) (4认同)
  • @hobs这是不正确的。桑德曼(Sandman)的代码对按列和按列进行规范化。如果转置,将得到错误的结果。 (2认同)

Mic*_*ina 42

根据这篇文章: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
Run Code Online (Sandbox Code Playgroud)

您无需担心自己的价值观是消极的还是积极的.并且值应该很好地分布在0和1之间.

  • 当最小值和最大值相同时要小心,您的分母为0,您将获得NaN值。 (4认同)
  • @AppajiChintimi,这个解决方案适用于整个数据,如果您没有进行健全性检查,您可能会遇到麻烦。 (3认同)

Pou*_*del 37

归一化方法的详细示例

  • Pandas 规范化(无偏)
  • Sklearn 归一化(有偏差)
  • 有偏见与无偏见会影响机器学习吗?
  • 混合最大缩放

参考资料: 维基百科:标准偏差的无偏估计

示例数据

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
Run Code Online (Sandbox Code Playgroud)

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

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

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
Run Code Online (Sandbox Code Playgroud)

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

如果你做同样的事情,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
Run Code Online (Sandbox Code Playgroud)

sklearn 的偏差估计是否会使机器学习不那么强大?

不。

sklearn.preprocessing.scale的官方文档指出,使用有偏估计器不太可能影响机器学习算法的性能,我们可以安全地使用它们。

来自官方文档:

我们对标准差使用有偏估计,相当于numpy.std(x, ddof=0)。请注意, 的选择ddof不太可能影响模型性能。

MinMax 缩放呢?

MinMax 缩放中没有标准偏差计算。所以结果在 pandas 和 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
Run Code Online (Sandbox Code Playgroud)


tsc*_*chm 29

你的问题实际上是一个简单的变换作用于列:

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

frame.apply(f, axis=0)
Run Code Online (Sandbox Code Playgroud)

或者更简洁:

   frame.apply(lambda x: x/x.max(), axis=0)
Run Code Online (Sandbox Code Playgroud)

  • 这不应该是axis=1,因为问题是列式归一化吗? (6认同)
  • `lambda` 是最好的 :-) (4认同)
  • 不,来自[文档](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.apply.html):`axis [...] 0或'index':将函数应用于每一列`。默认值实际上是“axis=0”,因此这一行可以写得更短:-)谢谢@tschm。 (3认同)
  • 仅当最小值为 0 时,这才是正确的,这不是您真正应该假设的 (2认同)

j s*_*sad 27

如果您喜欢使用sklearn包,可以使用pandas保留列名和索引名loc:

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler() 
scaled_values = scaler.fit_transform(df) 
df.loc[:,:] = scaled_values
Run Code Online (Sandbox Code Playgroud)


Bas*_*usa 21

简单即美:

df["A"] = df["A"] / df["A"].max()
df["B"] = df["B"] / df["B"].max()
df["C"] = df["C"] / df["C"].max()
Run Code Online (Sandbox Code Playgroud)

  • 注意,OP要求[0..1]范围,此解决方案可扩展到[-1..1]范围.尝试使用数组[-10,10]. (3认同)
  • @AlexanderSosnovshchenko不是真的。罗勒·穆萨(Basil Musa)假设OP的矩阵始终为非负数,这就是他给出此解决方案的原因。如果某列的条目为负,则此代码不会归一化为[-1,1]范围。尝试使用数组[-5,10]。用Cina的答案`df [“ A”] =(df [“ A”]-df [“ A”]。min())/(df [ “ A”]。max()-df [“ A”]。min())` (2认同)
  • **这个答案是错误的。** 这里不能做出非否定假设,因为OP和未来的读者都没有这么说。此外,即使是严格的正数在这里也不起作用:“[1, 10]”将被标准化为“[0.1, 1]”而不是“[0,1]”。 (2认同)

rau*_*ves 19

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

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
Run Code Online (Sandbox Code Playgroud)

您的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 ]
Run Code Online (Sandbox Code Playgroud)


Ben*_*ert 14

标准化

您可以使用minmax_scale将每列转换为 0-1 的范围。

from sklearn.preprocessing import minmax_scale
df[:] = minmax_scale(df)
Run Code Online (Sandbox Code Playgroud)

标准化

您可以使用scale将每列中心化为均值并缩放为单位方差。

from sklearn.preprocessing import scale
df[:] = scale(df)
Run Code Online (Sandbox Code Playgroud)

列子集

标准化单列

from sklearn.preprocessing import minmax_scale
df['a'] = minmax_scale(df['a'])
Run Code Online (Sandbox Code Playgroud)

仅标准化数字列

import numpy as np
from sklearn.preprocessing import minmax_scale
cols = df.select_dtypes(np.number).columns
df[cols] = minmax_scale(df[cols])
Run Code Online (Sandbox Code Playgroud)

完整示例

# Prep
import pandas as pd
import numpy as np
from sklearn.preprocessing import minmax_scale

# Sample data
df = pd.DataFrame({'a':[0,1,2], 'b':[-10,-30,-50], 'c':['x', 'y', 'z']})

# MinMax normalize all numeric columns
cols = df.select_dtypes(np.number).columns
df[cols] = minmax_scale(df[cols])

# Result
print(df)

#    a    b  c
# 0  0.0  1.0  x
# 2  0.5  0.5  y
# 3  1.0  0.0  z
Run Code Online (Sandbox Code Playgroud)

笔记:

在所有示例中scale都可以使用 来代替minmax_scale. 保持索引、列名或非数字变量不变。函数应用于每一列。

警告:

对于机器学习,请使用minmax_scaleor scale after train_test_split以避免数据泄露。

信息

有关标准化和规范化的更多信息:


Dan*_*ele 9

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

df = df/df.max().astype(np.float64)
Run Code Online (Sandbox Code Playgroud)

编辑如果您的数据框中存在负数,则应使用

df = df/df.loc[df.abs().idxmax()].astype(np.float64)
Run Code Online (Sandbox Code Playgroud)

  • 如果列的所有值都为零,则这将不起作用 (2认同)

Dav*_*jad 8

df_normalized = df / df.max(axis=0)
Run Code Online (Sandbox Code Playgroud)


cyb*_*ath 7

桑德曼和普拉文给出的解决方案非常好.唯一的问题是,如果您在数据框的其他列中有分类变量,则此方法需要进行一些调整.

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

 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])
Run Code Online (Sandbox Code Playgroud)

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

Yua*_*uan 7

这只是简单的数学。答案应该像下面一样简单。

normed_df = (df - df.min()) / (df.max() - df.min())
Run Code Online (Sandbox Code Playgroud)


Mas*_*dam 5

您可能希望某些列被规范化,而其他列则保持不变,例如某些回归任务,其中数据标签或分类列不变。因此,我建议您使用这种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()))
Run Code Online (Sandbox Code Playgroud)