AttributeError:“ float”对象没有属性“ max”

时间:2019-09-09 12:14:24

标签: python function

这是我先前的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

score1score2系列的可能值为-1和所有正整数(包括0)。我的目标是通过以下方式归一化这两个列:

  • 如果该值等于-1,则返回缺少的NaN
  • 否则,将01之间的范围内的剩余正整数归一化。

我对 ezrael solution感到非常满意。话虽如此,我仍在继续研究我的问题,以查看是否可以提出替代解决方案。这是我的尝试:

  1. 我正在定义以下功能:
def normalize(x):
    if x == -1:
        return np.nan
    else:
        return x/x.max()
  1. 我通过将上述功能应用于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/1515score1系列的最大值)替换了第二个“ 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的最大值,而不是对其进行硬编码。 为什么为什么我的解决方案不起作用,并且如何我要修复我的代码?

3 个答案:

答案 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()))