使熊猫的数据正常化

假设我有一个熊猫数据帧 df:

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

这很简单:

df.apply(average)

然后是列级范围 max (col)-min (col)。这也很简单:

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

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

非常感谢您的帮助/指点。

260486 次浏览
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

你可以使用 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

如果您不介意导入 sklearn库,我建议使用在 这个 blog 上讨论过的方法。

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

略微修改自: Python Panda Dataframe: 规范化0.01和0.99之间的数据?,但从一些评论认为它是相关的(抱歉,如果考虑转发...)

我希望定制的标准化在正常的百分位数或 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

这将采取一个熊猫系列,甚至只是一个列表,并规范化为您指定的低,中心和高点。还有一个缩水因素!所以你可以看到代码是如何工作的,但是基本上说你在一个样本中有值[ -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的值使用较深的颜色,而不是 hi/low。你可以根据标准化的数据绘制热图,其中 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”是最高值。

无论如何,我认为我的应用程序是相关的,如果你正在寻找重新规模的数据在其他方式,可以有有用的应用程序给你。

这就是你在专栏方面的做法:

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