这是我先前的post的延续,该规范是对Pandas DataFrame的列进行规范化,并带有特定的负值条件。
我正在使用的DataFrame如下:
import numpy as np
import pandas as pd
df = pd.DataFrame({'key' : [111, 222, 333, 444, 555, 666, 777, 888, 999],
'score1' : [-1, 0, 2, -1, 7, 0, 15, 0, 1],
'score2' : [2, 2, -1, 10, 0, 5, -1, 1, 0]})
print(df)
key score1 score2
0 111 -1 2
1 222 0 2
2 333 2 -1
3 444 -1 10
4 555 7 0
5 666 0 5
6 777 15 -1
7 888 0 1
8 999 1 0
score1
和score2
系列的可能值为-1
和所有正整数(包括0
)。我的目标是通过以下方式归一化这两个列:
-1
,则返回缺少的NaN
值0
和1
之间的范围内的剩余正整数归一化。我对 ezrael 的solution感到非常满意。话虽如此,我仍在继续研究我的问题,以查看是否可以提出替代解决方案。这是我的尝试:
def normalize(x):
if x == -1:
return np.nan
else:
return x/x.max()
norm1
系列来创建新的score1
系列:df['norm1'] = df['score1'].apply(normalize)
不幸的是,这引发了以下AttributeError: 'int' object has no attribute 'max'
。
我将score1
系列转换为float64
,但不能解决问题:'float' object has no attribute 'max'
。
我还通过用return x/15
(15
是score1
系列的最大值)替换了第二个“ return”语句来进行了快速测试,并且有效:
key score1 score2 norm1
0 111 -1.0 2 NaN
1 222 0.0 2 0.000000
2 333 2.0 -1 0.133333
3 444 -1.0 10 NaN
4 555 7.0 0 0.466667
5 666 0.0 5 0.000000
6 777 15.0 -1 1.000000
7 888 0.0 1 0.000000
8 999 1.0 0 0.066667
但这不是可行的解决方案。我希望能够除以Series的最大值,而不是对其进行硬编码。 为什么为什么我的解决方案不起作用,并且如何我要修复我的代码?
答案 0 :(得分:2)
AttributeError: 'float' object has no attribute 'max'
错误的原因是,使用代码在列的每个(浮动)项目上调用max()函数,您可以将列的最大值传递给{{1} }函数:
normalize
并按如下所示编辑norm1列创建代码:
def normalize(x, col_max):
if x == -1:
return np.nan
else:
return x/col_max
答案 1 :(得分:1)
另一种解决方案,使用以系列而不是标量作为输入的函数:
import numpy as np
import pandas as pd
df = pd.DataFrame({'key' : [111, 222, 333, 444, 555, 666, 777, 888, 999],
'score1' : [-1, 0, 2, -1, 7, 0, 15, 0, 1],
'score2' : [2, 2, -1, 10, 0, 5, -1, 1, 0]})
df['norm1'] = df['score1'].replace(-1, np.nan)
def normalize_series(s):
return (s - s.min()) / (s.max() - s.min())
df['norm1'] = normalize_series(df['norm1'])
如前所述,您的版本无法正常运行,因为您要查找单个数字而不是一个序列的最大值。
答案 2 :(得分:1)
了解“ apply”函数的作用很重要:“ apply”的“ x”参数实际上是一行(如果将f应用于pd.Dataframe对象),或者直接是该行的唯一值(如果要操作pd.Series对象)。
您处于第二种情况。想象一下,有一个列表而不是pd.Series。
L = [1,2,3,4,5]
def normalize(x):
return(x/max(x))
normalize(L)
很明显,max(x)没有任何意义。您正在寻找的是max(L)
。
所以从技术上讲这是可以的:
L = [1,2,3,4,5]
def normalize(x):
return(x/max(L))
normalize(L)
但是效率不高,因为您每次迭代都会重新计算max(L)。所以
L = [1,2,3,4,5]
max_L = max(L)
def normalize(x,max_L):
return(x/max_L)
normalize(L)
将是您正在寻找的答案。使用pd.Series,它可以提供
def normalize(x, col_max):
if x == -1:
return np.nan
else:
return x/col_max
df['norm1'] = df['score1'].apply(lambda x: normalize(x, df['score1'].max()))
请注意,不必用-1代替NaN来计算min()和max(),只需使用nanmin()和nanmax()。您可以这样分开操作:
def create_nans(x):
if x == -1:
return np.nan
else:
return x
def normalize(x, col_max):
return(x/col_max) # make sure col_max != 0 or NaN
df['score1'] = df['score1'].apply(create_nans)
df['norm1'].apply(lambda x: normalize(x, df['score1'].nanmax()))