我在这里读到了两个问题:
- 如何处理多个学生和阈值?
- 我怎样才能做到这一点?
我将专注于“我如何快速完成此操作”的答案,因为三个答案已经提到如何处理多个学生。
这里有两个步骤:
-
Profile your code 查找花费最多的时间。轶事:通常有一小部分紧密循环,您的程序在其中花费了大部分运行时间。我在这里跳过了这一步,但对于更复杂的示例,这是必需的。
-
Benchmark snippets 并根据需要优化,甚至重写 lower-level language。
这是您的代码版本 + @nbrix 的答案。我已经修改了check_grade 方法以返回True 或False 以与下面显示的numpy 版本保持一致。
class StudentGrades:
def __init__(self, scores):
self.scores = scores
def average(self):
return sum(self.scores) / len(self.scores)
def check_grade(self, threshold=0.7):
avg = self.average()
if avg >= threshold:
return True
return False
def run_student_grades(data):
return [StudentGrades(scores).check_grade() for scores in data]
这是我使用numpy 编写的一个函数,它计算平均值以及平均值是否大于0.7 阈值:
import numpy as np
def run_numpy_student_grades(data):
return np.mean(data, axis=1) > 0.7
对于少量输入(两个学生,两个作业),它们之间可能没有区别。事实上,使用numpy 稍微慢:
- benchmark 'Small Input: Two Students, Two Assignments': 2 tests -
Name (time in us) Mean Median
-------------------------------------------------------------------
test_pure_python_small_input 4.9058 (1.0) 4.9330 (1.0)
test_numpy_small_input 8.5494 (1.74) 8.5580 (1.73)
-------------------------------------------------------------------
对于大量输入(此处:1000 名学生,每人有 100 份作业),两者之间的差异很大:numpy 版本比初始化对象和列表的 Python 版本快约 250 倍理解他们。
------ benchmark 'Big Input: 1000 Students, 100 Assignments': 2 tests -----
Name (time in us) Mean Median
---------------------------------------------------------------------------
test_numpy_big_input 55.5528 (1.0) 56.1480 (1.0)
test_pure_python_big_input 13,675.3789 (246.17) 13,865.2100 (246.94)
---------------------------------------------------------------------------
哪个版本在实践中是正确的取决于您的数据和其他外部因素:例如您将实际与多少学生和作业一起工作。
这里是基准代码,假设实现了run_* 方法:
# File: `benchmark.py`
# Install: `pip install pytest pytest-benchmark numpy`
# Run with: `pytest benchmark.py`
import pytest
from demo_plain import run_student_grades
from demo_numpy import run_numpy_student_grades
import numpy as np
from numpy.random import default_rng
rng = default_rng(42)
two_students_two_assignments = np.array([[0.8, 0.9], [0.6, 0.2]])
thousand_students_hundred_assignments = rng.standard_normal(size=(1000, 100))
@pytest.mark.benchmark(group="Small Input: Two Students, Two Assignments")
def test_pure_python_small_input(benchmark):
result = benchmark(run_student_grades, two_students_two_assignments)
@pytest.mark.benchmark(group="Small Input: Two Students, Two Assignments")
def test_numpy_small_input(benchmark):
result = benchmark(run_numpy_student_grades, two_students_two_assignments)
@pytest.mark.benchmark(group="Big Input: 1000 Students, 100 Assignments")
def test_pure_python_big_input(benchmark):
result = benchmark(run_student_grades, thousand_students_hundred_assignments)
@pytest.mark.benchmark(group="Big Input: 1000 Students, 100 Assignments")
def test_numpy_big_input(benchmark):
result = benchmark(run_numpy_student_grades, thousand_students_hundred_assignments)
它是分开的,但这里有一个处理多个阈值的版本:
def run_numpy_student_grades_thresholds(data, thresholds):
_avg = np.mean(data, axis=1)
return np.c_[
[_avg > threshold for threshold in thresholds]
]
print(run_numpy_student_grades_thresholds([[0.8, 0.9], [0.6, 0.2]], [0.7, 0.9]))
# [[ True False]
# [False False]]