【问题标题】:Normalize data in pandas规范化 pandas 中的数据
【发布时间】:2012-09-13 14:13:10
【问题描述】:

假设我有一个熊猫数据框df

我想计算数据框的列平均值。

这很简单:

df.apply(average) 

然后按列范围 max(col) - min(col)。这又很容易:

df.apply(max) - df.apply(min)

现在对于每个元素,我想减去其列的平均值并除以其列的范围。我不知道该怎么做

非常感谢任何帮助/指针。

【问题讨论】:

    标签: python pandas numpy


    【解决方案1】:
    In [92]: df
    Out[92]:
               a         b          c         d
    A  -0.488816  0.863769   4.325608 -4.721202
    B -11.937097  2.993993 -12.916784 -1.086236
    C  -5.569493  4.672679  -2.168464 -9.315900
    D   8.892368  0.932785   4.535396  0.598124
    
    In [93]: df_norm = (df - df.mean()) / (df.max() - df.min())
    
    In [94]: df_norm
    Out[94]:
              a         b         c         d
    A  0.085789 -0.394348  0.337016 -0.109935
    B -0.463830  0.164926 -0.650963  0.256714
    C -0.158129  0.605652 -0.035090 -0.573389
    D  0.536170 -0.376229  0.349037  0.426611
    
    In [95]: df_norm.mean()
    Out[95]:
    a   -2.081668e-17
    b    4.857226e-17
    c    1.734723e-17
    d   -1.040834e-17
    
    In [96]: df_norm.max() - df_norm.min()
    Out[96]:
    a    1
    b    1
    c    1
    d    1
    

    【讨论】:

    • 如果你想标准化一个子集,有没有办法做到这一点?假设行 AB 是您希望与 CD 分开标准化的更大分组因子的一部分。
    • 选择子集并像以前一样计算。请参阅pandas.pydata.org/pandas-docs/stable/indexing.html 了解如何索引和选择数据
    • 如果你需要你的值 > 0:df_norm = (df - df.min()) / (df.max() - df.min())
    • 应该是 df_norm = (df - df.min()) / (df.max() - df.min()) 而不是第一个括号中的 df.mean() 来获取值在 0 到 1 之间
    • 如果您的数据框在某些列中有字符串,请参阅answer
    【解决方案2】:

    这个你可以用apply,这样更简洁一些:

    import numpy as np
    import pandas as pd
    
    np.random.seed(1)
    
    df = pd.DataFrame(np.random.randn(4,4)* 4 + 3)
    
              0         1         2         3
    0  9.497381  0.552974  0.887313 -1.291874
    1  6.461631 -6.206155  9.979247 -0.044828
    2  4.276156  2.002518  8.848432 -5.240563
    3  1.710331  1.463783  7.535078 -1.399565
    
    df.apply(lambda x: (x - np.mean(x)) / (np.max(x) - np.min(x)))
    
              0         1         2         3
    0  0.515087  0.133967 -0.651699  0.135175
    1  0.125241 -0.689446  0.348301  0.375188
    2 -0.155414  0.310554  0.223925 -0.624812
    3 -0.484913  0.244924  0.079473  0.114448
    

    此外,如果您选择相关的列,它可以很好地与 groupby 配合使用:

    df['grp'] = ['A', 'A', 'B', 'B']
    
              0         1         2         3 grp
    0  9.497381  0.552974  0.887313 -1.291874   A
    1  6.461631 -6.206155  9.979247 -0.044828   A
    2  4.276156  2.002518  8.848432 -5.240563   B
    3  1.710331  1.463783  7.535078 -1.399565   B
    
    
    df.groupby(['grp'])[[0,1,2,3]].apply(lambda x: (x - np.mean(x)) / (np.max(x) - np.min(x)))
    
         0    1    2    3
    0  0.5  0.5 -0.5 -0.5
    1 -0.5 -0.5  0.5  0.5
    2  0.5  0.5  0.5 -0.5
    3 -0.5 -0.5 -0.5  0.5
    

    【讨论】:

      【解决方案3】:

      如果您不介意导入sklearn 库,我会推荐this 博客上讨论的方法。

      import pandas as pd
      from sklearn import preprocessing
      
      data = {'score': [234,24,14,27,-74,46,73,-18,59,160]}
      cols = data.columns
      df = pd.DataFrame(data)
      df
      
      min_max_scaler = preprocessing.MinMaxScaler()
      np_scaled = min_max_scaler.fit_transform(df)
      df_normalized = pd.DataFrame(np_scaled, columns = cols)
      df_normalized
      

      【讨论】:

      • 博客文章的链接已失效。你有工作的吗?
      • 创建单位正态归一化数据的相应方法称为StandardScaler。
      • 我在另一个地方找到了类似的解决方案。问题是在 np_scaled 部分,它显示了一个错误,期望 2D 数组,但输入是 1D 数组,它建议我们使用 reshape(-1,1)。知道如何解决这个问题,因为 reshape 也不起作用。?
      • 您可能会收到警告,具体取决于您使用的 numpy 和 sklearn 版本,但总的来说,这应该可以工作 np_scaled = min_max_scaler.fit_transform(df.score.astype(float).values.reshape(-1, 1))
      【解决方案4】:

      略微修改自:Python Pandas Dataframe: Normalize data between 0.01 and 0.99?,但一些 cmets 认为它​​是相关的(抱歉,如果考虑转贴...)

      我希望在常规的基准百分位数或 z 分数不够的情况下进行自定义归一化。有时我知道总体的可行最大值和最小值是多少,因此想要定义它而不是我的样本,或者不同的中点,或其他任何东西!这通常对于重新缩放和规范化神经网络的数据很有用,您可能希望所有输入都在 0 和 1 之间,但您的某些数据可能需要以更自定义的方式缩放......因为百分位数和标准差假设您的样本涵盖人口,但有时我们知道这不是真的。在热图中可视化数据时,它对我也非常有用。所以我构建了一个自定义函数(在此处的代码中使用了额外的步骤以使其尽可能可读):

      def NormData(s,low='min',center='mid',hi='max',insideout=False,shrinkfactor=0.):    
          if low=='min':
              low=min(s)
          elif low=='abs':
              low=max(abs(min(s)),abs(max(s)))*-1.#sign(min(s))
          if hi=='max':
              hi=max(s)
          elif hi=='abs':
              hi=max(abs(min(s)),abs(max(s)))*1.#sign(max(s))
      
          if center=='mid':
              center=(max(s)+min(s))/2
          elif center=='avg':
              center=mean(s)
          elif center=='median':
              center=median(s)
      
          s2=[x-center for x in s]
          hi=hi-center
          low=low-center
          center=0.
      
          r=[]
      
          for x in s2:
              if x<low:
                  r.append(0.)
              elif x>hi:
                  r.append(1.)
              else:
                  if x>=center:
                      r.append((x-center)/(hi-center)*0.5+0.5)
                  else:
                      r.append((x-low)/(center-low)*0.5+0.)
      
          if insideout==True:
              ir=[(1.-abs(z-0.5)*2.) for z in r]
              r=ir
      
          rr =[x-(x-0.5)*shrinkfactor for x in r]    
          return rr
      

      这将采用 pandas 系列,甚至只是一个列表,并将其标准化为您指定的低点、中心点和高点。还有缩水的因素!允许您从端点 0 和 1 缩小数据(在 matplotlib 中组合颜色图时我必须这样做:Single pcolormesh with more than one colormap using Matplotlib)所以您可能会看到代码是如何工作的,但基本上说您有值 [-5, 1,10] 在样本中,但希望基于 -7 到 7 的范围进行归一化(因此任何高于 7 的值,我们的“10”都被有效地视为 7),中点为 2,但缩小它以适应256 RGB 颜色图:

      #In[1]
      NormData([-5,2,10],low=-7,center=1,hi=7,shrinkfactor=2./256)
      #Out[1]
      [0.1279296875, 0.5826822916666667, 0.99609375]
      

      它还可以将您的数据翻过来……这可能看起来很奇怪,但我发现它对热图很有用。假设您想要更接近 0 而不是高/低的值的颜色更深。您可以根据 insideout=True 的规范化数据进行热图:

      #In[2]
      NormData([-5,2,10],low=-7,center=1,hi=7,insideout=True,shrinkfactor=2./256)
      #Out[2]
      [0.251953125, 0.8307291666666666, 0.00390625]
      

      所以现在离中心最近的“2”,定义为“1”是最大值。

      无论如何,如果您希望以其他可能对您有用的应用程序的方式重新调整数据,我认为我的应用程序是相关的。

      【讨论】:

      • 您可以将所有 if/else 语句替换为 dictionary with functions。那样看起来干净一些。
      • 写的真好,下次记住了,谢谢!
      【解决方案5】:

      这是按列进行的:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-05-31
        • 1970-01-01
        • 2012-08-21
        • 2013-12-11
        • 2019-12-22
        • 2019-03-25
        • 2020-12-15
        • 1970-01-01
        相关资源
        最近更新 更多