【问题标题】:How to round a number to a chosen integer如何将数字四舍五入为选定的整数
【发布时间】:2016-06-17 09:26:29
【问题描述】:

在丹麦,我们有一个奇怪的评分系统,如下所示。 [-3,00,02,4,7,10,12] 我们的任务是取一个具有不同十进制数的向量,并将其四舍五入到最接近的有效等级。到目前为止,这是我们的代码。

import numpy as np

def roundGrade(grades):    
    if (-5<grades<-1.5):
        gradesRounded = -3
    elif (-1.5<=grades<1.5):
        gradesRounded = 00
    elif (1.5<=grades<3):
        gradesRounded = 2
    elif (3<=grades<5.5):
        gradesRounded = 4
    elif (5.5<=grades<8.5):
        gradesRounded = 7
    elif (8.5<=grades<11):
        gradesRounded = 10
    elif (11<=grades<15):
        gradesRounded = 12
    return gradesRounded

print(roundGrade(np.array[-2.1,6.3,8.9,9]))

我们的控制台似乎不喜欢这样并重新调整: TypeError: builtin_function_or_method' 对象不可下标

感谢所有帮助,如果您有更聪明的方法,欢迎您将我们置于我们的位置。

【问题讨论】:

  • 这里绝对不需要numpy。
  • @Ev.Kounis 我假设使用 numpy 是有充分理由的,这只是一个玩具示例,否则我建议简单地使用带有内置 @987654322 的列表@函数。

标签: python numpy rounding


【解决方案1】:

您收到该错误是因为您在打印时使用了不正确的语法:

print(roundGrade(np.array[-2.1,6.3,8.9,9]))

需要

print(roundGrade(np.array([-2.1,6.3,8.9,9])))

注意多余的括号:np.array(&lt;whatever&gt;)

但是,这不起作用,因为您的函数需要一个数字。幸运的是,numpy 提供了一个可以为你解决这个问题的函数:

In [15]: roundGrade = np.vectorize(roundGrade)

In [16]: roundGrade(np.array([-2.1,6.3,8.9,9]))
Out[16]: array([-3,  7, 10, 10])

http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.vectorize.html

【讨论】:

    【解决方案2】:

    您可以简单地采用从每个年级到每个年级组的最小距离,就像这样。这假设您实际上想要四舍五入到您的成绩组中最接近的成绩,而您当前的代码并不完全这样做。

    grade_groups = [-3,0,2,4,7,10,12]
    sample_grades = [-2.1,6.3,8.9,9]
    grouped = [min(grade_groups,key=lambda x:abs(grade-x)) for grade in sample_grades]
    print(grouped)
    

    输出

    [-3, 7, 10, 10]
    

    请注意,即使在修复了错误之后,您的方法也不会起作用,因为 roundGrade 需要一个数字作为参数。 As shown by juanapa 你可以矢量化你的函数。

    【讨论】:

      【解决方案3】:

      我会通过计算它最接近哪个有效等级并返回那个来四舍五入:

      import numpy as np
      def roundGrade(grade):
          validGrades = np.array([-3,0,2,4,7,10,12])
          return validGrades[np.argmin((grade-validGrades)**2)]
      

      这当然只允许您一次通过一个成绩,但您可以在函数外部或内部循环遍历小数数组以使其与数组兼容。

      【讨论】:

        【解决方案4】:
        def roundGrade(grade):
            d = {x:abs(x - grade) for x in [-3,00,02,4,7,10,12]}
            return min(d, key=d.get)
        print list(map(roundGrade, [-2.1, 6.3, 8.9, 9]))
        

        效率较低(我认为)但代码要小得多
        它创建一个字典,其中键是一个圆形等级,值是圆形等级和给定等级之间的差异
        然后它找到最小值(最小差)并返回键(四舍五入的值
        然后它只是使用map 将此函数应用于列表中的每个项目

        【讨论】:

          【解决方案5】:

          我认为您可以仅使用列表在一个班轮中完成此操作:

          l = [-2.1,6.3,8.9,9]
          b = [-3,0,02,4,7,10,12]
          
          a = [b[min(enumerate([abs(j - item) for j in b]), key=lambda p:p[1])[0]] for item in l]
          >>> [-3, 7, 10, 10]
          

          您可以将其分解为:

          min(enumerate([abs(j - item) for j in b]), key=lambda p:p[1])[0]  # Find the index of the nearest grade boundary
          [b[...] for item in l]  # Get the associated grade boundary for all the items in the original list
          

          【讨论】:

            【解决方案6】:

            好吧,即使没有测试您的代码,我也可以在这里看到一些问题。

            您的函数roundGrade 接受一个数字并返回一个数字,但是当您调用它时,您会为其提供一个数组。假设您的缩进没问题并且调用不在函数内部,我会这样做:

            def roundGrade(grades):
            
                if (-5<grades<-1.5):
                    gradesRounded = -3
                elif (-1.5<=grades<1.5):
                    gradesRounded = 00
                elif (1.5<=grades<3):
                    gradesRounded = 2
                elif (3<=grades<5.5):
                    gradesRounded = 4
                elif (5.5<=grades<8.5):
                    gradesRounded = 7
                elif (8.5<=grades<11):
                    gradesRounded = 10
                elif (11<=grades<15):
                    gradesRounded = 12
                return gradesRounded
            
            #print(roundGrade(np.array[-2.1,6.3,8.9,9]))
            # Here, I assume you want to round each of the grades in the array. If I'm wrong, comment, please!
            
            for i in [-2.1, 6.3, 8.9, 9]:
                print roundGrade(i)
            

            调用该方法并提供一个数组是不行的,而用每个​​元素调用该方法是可以的,因为该方法应该接收一个数字而不是一个数组。

            【讨论】:

              【解决方案7】:

              我就是这样做的:

              def roundGrade(grades_in):
                  grades_out = []
                  for grades in grades_in:
                      if grades < -5 or grades > 15:
                          gradesRounded = '??'
                          print('Grade input out of range ({:})!'.format(grades))
                      if (-5<grades<-1.5):
                          gradesRounded = '-3'
                      elif (-1.5<=grades<1.5):
                          gradesRounded = '00'
                      elif (1.5<=grades<3):
                          gradesRounded = '2'
                      elif (3<=grades<5.5):
                          gradesRounded = '4'
                      elif (5.5<=grades<8.5):
                          gradesRounded = '7'
                      elif (8.5<=grades<11):
                          gradesRounded = '10'
                      elif (11<=grades<15):
                          gradesRounded = '12'
                      grades_out.append(gradesRounded)
                  return grades_out
              
               grades_in = [-7, -2.1, 0.1, 6.3, 8.9, 9]
               print(roundGrade(grades_in))  #prints: ['??', '-3', '00', '7', '10', '10']
              

              获取一个列表并返回一个。处理超出范围的输入和返回的列表项是字符串而不是整数,以添加花哨的“00”而不是“0”。

              【讨论】:

                【解决方案8】:

                由于行中的额外括号,您会收到该错误

                print(roundGrade(np.array([-2.1,6.3,8.9,9])))
                

                应该是

                print(roundGrade(np.array[-2.1,6.3,8.9,9]))
                

                【讨论】:

                  【解决方案9】:

                  至于异常,numpy数组是一个函数,需要用()调用 所以你的方法调用应该是这样的:

                  print(roundGrade(np.array([-2.1,6.3,8.9,9])))
                  

                  而不是:

                  print(roundGrade(np.array[-2.1,6.3,8.9,9]))
                  

                  至于函数本身,要么使用 grades.any()grades.all() 测试整个元素,否则不定义比较。

                  【讨论】:

                    【解决方案10】:

                    我建议在这里使用numpy.digitize,因为它可以让您轻松地向量化这个操作。

                    设置

                    bins = np.array([-5, -1.5, 1.5, 3, 5.5, 8.5, 11, 15])
                    outputs = np.array([-3,  0,  2,  4,  7, 10, 12])
                    
                    grades = np.array([-2.1,  6.3,  8.9,  9. ])
                    

                    使用 numpy.digitize

                    outputs[np.digitize(grades, bins)-1]
                    

                    array([-3,  7, 10, 10])
                    

                    即使其他答案已显示如何使用 np.vectorizedigitize 在合并值时仍会为您提供很大的性能提升:

                    _v_round_grade = np.vectorize(roundGrade)
                    grades = np.random.randint(-4, 14, 10000)
                    

                    In [496]: %timeit _v_round_grade(grades)
                    5.64 ms ± 24.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
                    
                    In [497]: %timeit outputs[np.digitize(grades, bins)-1]
                    210 µs ± 567 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
                    

                    验证

                    >>> np.array_equal(_v_round_grade(grades), outputs[np.digitize(grades, bins)-1])
                    True
                    

                    使用这个内置的 digitize 函数比简单地向量化您自己的函数要快 25 倍

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-01-26
                      • 2015-12-05
                      • 1970-01-01
                      • 2014-08-26
                      • 1970-01-01
                      相关资源
                      最近更新 更多