用class来计算python的平均值

时间:2015-08-09 10:44:07

标签: python class python-2.7

我正在使用python从一系列空气质量监视器中读取数据。

目前,我正在关注计算平均值。我认为必须有一种更好的方法来使用类来实现这一点,因为大多数代码都会重复,以使其更加普遍适用和高效。

另一个问题是我有许多不同类型的显示器,它们主要以相同的原理运行,但变量略有不同。下面给出的代码是一个真正的噩梦,转移到一个新的监视器,因为我必须编辑每一行。

麻烦的是,当我搜索课程和平均时,我似乎得到的是在学校课堂上平均学生成绩,而不是使用软件类来计算多个变量的平均值。

基本上显示器只读一秒钟,但我只需要1分钟的平均值,所以我会一直播放,直到分钟翻身。

感激地收到任何建议。

目前我正在这样做:

while minute unchanged:
    ## read serial port

    readData = SER.read()  

    ## Split comma delimited data into dust, flow, temperature, relative humidity, pressure
    ## for example data comes in as 000.007,2.0,+21.7,046,1010.0
    measData = readData[0].split(',')           
    dustReading = measData[0].strip()                       

    flowReading = measData[1]
    flowReading = flowReading.strip()

    tempReading = measData[2]
    tempReading = tempReading.strip()

    rhReading = measData[3]
    rhReading = rhReading.strip()

    pressReading = measData[4]
    pressReading = pressReading.strip()


    ######### Dust #######

    try :   
        nReading = nReading+1   
        dustReading = float(dustReading)
        sumDustReading = sumDustReading + dustReading
        meanDustReading = sumReading/float(nReading)            
    except :
         pass       

    ####### Flow ##########
    try :   
        flowReading = float(flowReading)
        sumFlowReading = sumFlowReading+flowReading
        meanFlowReading = float(sumFlowReading)/float(nReading)
    except :
         pass                       

    ######## Temperature #########
    try:    
        tempReading = float(tempReading)
        sumTempReading = sumTempReading+tempReading
        meanTempReading = float(sumTempReading)/float(nReading)
    except :
         pass

    ######### RH ########
    try :   
        rhReading = float(rhReading)
        sumRhReading = sumRhReading+rhReading
        meanRhReading = float(sumRhReading)/float(nReading)
    except :
         pass       

    ###### Pressure Reading ######
    try :   
        pressReading = float(pressReading)
        sumPressReading = sumPressReading+pressReading
        meanPressReading = float(sumPressReading)/float(nReading)               
    except :
        pass

理想情况下,我希望能够得到像

这样的东西
flow.mean
flow.numberOfReads
flow.sum

万分感谢。

2 个答案:

答案 0 :(得分:2)

您现有的代码有点奇怪&所有try:...except块都很危险。它很危险,因为它忽略了真正应该被忽略的各种错误。例如:尝试使用未定义变量的值,除以零错误和完全语法错误。

可以在课堂上做你想做的事,但对于这样的事情,我更有可能使用简单的dict。我会发布两种方法的代码,以帮助您决定(或增加您的困惑:))。

显然,我没有将监控硬件连接到我的串口,所以为了测试这段代码,我编写了一个简单的生成器函数来创建随机假数据。希望您能够轻松修改我的代码。

首先,使用保存当前总数和读数的类的代码;此类还有一个按需计算平均值的属性。因此,如果您愿意,可以执行print dust.total, flow.mean之类的操作。

from random import seed, random

#A generator to make simulated data
def fake_data(n):
    for i in range(n):
        d = 0.005 + 0.005 * random()
        f = 1.5 + random()
        t = 20.0 + 5.0 * random()
        h = int(40 + 10.0 * random())
        p = 1005.0 + 10.0 * random()

        s = '%07.3f,%3.1f,%-4.1f,%03d,%6.1f' % (d, f, t, h, p)
        yield [s]


class Data(object):
    def __init__(self, name):
        self.name = name
        self.total = 0
        self.numberOfReads = 0

    def __repr__(self):
        fmt = "Data(name='%s', total=%f, number=%d, mean=%f)"
        return fmt % (self.name, self.total, self.numberOfReads, self.mean)

    def __str__(self):
        fmt = '%s\nmean: %f\nnumber: %d\ntotal: %f\n'
        return fmt % (self.name, self.mean, self.numberOfReads, self.total)

    def add(self, value):
        self.total += value
        self.numberOfReads += 1

    @property
    def mean(self):
        try:
            return float(self.total) / float(self.numberOfReads)
        except ZeroDivisionError:
            return None


#Seed the randomiser
seed(1)

#Initialise the Data instances
dust = Data('Dust')
flow = Data('Flow')
temp = Data('Temperature')
rh = Data('Relative Humidity')
press = Data('Pressure')

for readData in fake_data(10):
    ## Split comma delimited data into dust, flow, temperature, relative humidity, pressure
    ## for example data comes in as 000.007,2.0,+21.7,046,1010.0
    print readData
    measData = readData[0].split(',')

    #Convert data strings to floats
    dustR, flowR, tempR, rhR, pressR = [float(s) for s in measData]

    #Add new data to current totals
    dust.add(dustR)
    flow.add(flowR)
    temp.add(tempR)
    rh.add(rhR)
    press.add(pressR)

print

for a in (dust, flow, temp, rh, press):
    print a

<强>输出

['000.006,2.3,23.8,042,1010.0']
['000.007,2.2,23.9,040,1005.3']
['000.009,1.9,23.8,040,1009.5']
['000.009,1.7,24.7,049,1005.3']
['000.005,2.0,24.7,043,1007.2']
['000.007,1.5,21.1,044,1010.0']
['000.006,1.7,21.1,044,1007.9']
['000.005,2.3,22.8,046,1006.9']
['000.010,2.4,20.6,043,1012.2']
['000.009,2.4,22.1,048,1011.7']

Dust
mean: 0.007300
number: 10
total: 0.073000

Flow
mean: 2.040000
number: 10
total: 20.400000

Temperature
mean: 22.860000
number: 10
total: 228.600000

Relative Humidity
mean: 43.900000
number: 10
total: 439.000000

Pressure
mean: 1008.600000
number: 10
total: 10086.000000

这是使用dict的版本。我已将随机数种子设置为相同的值,以便假数据与之前版本相同。

from random import seed, random

#A generator to make simulated data
def fake_data(n):
    for i in range(n):
        d = 0.005 + 0.005 * random()
        f = 1.5 + random()
        t = 20.0 + 5.0 * random()
        h = int(40 + 10.0 * random())
        p = 1005.0 + 10.0 * random()

        s = '%07.3f,%3.1f,%-4.1f,%03d,%6.1f' % (d, f, t, h, p)
        yield [s]


#Seed the randomiser
seed(1)

#data field names
fields = ('Dust', 'Flow', 'Temp', 'rh', 'press')

#initialise the data dictionary 
data = dict.fromkeys(fields, 0.0)

nReading = 0
for readData in fake_data(10):
    nReading += 1

    ## Split comma delimited data into dust, flow, temperature, relative humidity, pressure
    ## for example data comes in as 000.007,2.0,+21.7,046,1010.0
    print nReading, readData
    measData = readData[0].split(',')

    #Convert data strings to floats
    floatData = [float(s) for s in measData]

    #Add new data to current totals
    for key, value in zip(fields, floatData):
        data[key] += value

print '\nNumber of readings = %d\n' % nReading
nReading = float(nReading)
for key in fields:
    total = data[key]
    mean = total / nReading
    print '%s\nmean: %f\ntotal: %f\n' % (key, mean, total)

<强>输出

1 ['000.006,2.3,23.8,042,1010.0']
2 ['000.007,2.2,23.9,040,1005.3']
3 ['000.009,1.9,23.8,040,1009.5']
4 ['000.009,1.7,24.7,049,1005.3']
5 ['000.005,2.0,24.7,043,1007.2']
6 ['000.007,1.5,21.1,044,1010.0']
7 ['000.006,1.7,21.1,044,1007.9']
8 ['000.005,2.3,22.8,046,1006.9']
9 ['000.010,2.4,20.6,043,1012.2']
10 ['000.009,2.4,22.1,048,1011.7']

Number of readings = 10

Dust
mean: 0.007300
total: 0.073000

Flow
mean: 2.040000
total: 20.400000

Temp
mean: 22.860000
total: 228.600000

rh
mean: 43.900000
total: 439.000000

press
mean: 1008.600000
total: 10086.000000

以下是使用try:... except验证输入数据的简单示例。

data = [
    '1.1 2.2 3.3',
    '4 5',
    '6 garbage bytes',
    '7 8 9 10',
    '11 12 13',
]

for i, line in enumerate(data):
    print '\nLine %d: %r' % (i, line)
    row = line.split()
    if len(row) != 3:
        print 'Bad row length. Should be 3 not', len(row)
        continue

    try:
        a, b, c = [float(s) for s in row]
    except ValueError as err:
        print 'Conversion error:', err
        continue

    print 'Data %d: a=%f, b=%f, c=%f' % (i, a, b, c)

<强>输出

Line 0: '1.1 2.2 3.3'
Data 0: a=1.100000, b=2.200000, c=3.300000

Line 1: '4 5'
Bad row length. Should be 3 not 2

Line 2: '6 garbage bytes'
Conversion error: invalid literal for float(): garbage

Line 3: '7 8 9 10'
Bad row length. Should be 3 not 4

Line 4: '11 12 13'
Data 4: a=11.000000, b=12.000000, c=13.000000

答案 1 :(得分:1)

如果将数据保存在列表中,则更容易计算平均值和其他统计属性。诸如列表长度和总和之类的东西都是内置的。

首先制作一些清单。

dust, flow, temp, rh, pressure = [], [], [], [], []

我将使用以下数据作为示例。

readData = '000.007,2.0,+21.7,046,1010.0'

让我们把它分开;

newdust, newflow, newtemp, newrh, newpressure = [float(n) for n in readData.split(',')]
dust.append(newdust)
...
pressure.append(newpressure)

计算平均值:

sum(pressure)/len(pressure)

<强>更新

很难给出处理不同类型仪器的建议,而不会看到它们产生的数据。

例如,您可以为每种不同类型的传感器编写数据转换函数,该函数从串行端口读取一行并返回tuplenamedtuple数据,并且不支持测量由特定设备None。 假设您知道您连接的传感器可以选择正确的功能,以便在程序开头调用;

from collections import namedtuple

Instrumentrecord = namedtuple('Instrumentrecord',
                              ['dust', 'flow', 'temp', 'humidity', 
                               'pressure', 'windspeed', 'winddir'])

def foo_sensor(dataline):
    dust, flow, temp, rh, pressure = [float(n) for n in dataline.split(',')]
    return Instrumentrecord(dust, flow, temp, rh, pressure, None, None)


def main(argv):
    ....
    if sensortype == 'foo':
        current_sensor = foo_sensor
    ...
    data = []
    while keep_going:
        line = SER.read()
        data.append(current_sensor(line))