I am new in Python, but I have laboratory work with some routine computing, so I have decided do these calculations in Python.
Program input is physical characteristic, measured several times (i.e list of floats). The program calculates average value and square average deviation for the list. After this, it makes table of intermediate calculations (I need to record this table in the laboratory work) and prints it. Then, using square average deviations, the program checks for data that are suspect for a measurement error. If wrong data exist, the programm removes it and recalculate and reprint average value, square average deviation and table. After this, the program calculates and prints random and relative measurement error and also prints answer.
The program works, but I am worrying about its design and structure.
- Is it a common practice for Python programmers to first place import statements, then some functions and then main part of program? Is there a more readable program code structure?
- Are multi-line comments (i.e.
""" """
) a standard of de facto Python programming or are there are common standards for multi-line commenting? - Is there a common code style for Python community for function's comments?
Code:
#!/usr/bin/env python3
import sys
import math
import decimal
from prettytable import PrettyTable
from functools import reduce
from collections import Counter
ctx = decimal.Context()
ctx.prec = 20
def toFixedStr(f):
d1 = ctx.create_decimal(repr(f))
return format(d1, 'f')
# Round only significant digits
def roundSig(x, sig=2):
if x != 0.0:
return round(x, sig-int(math.floor(math.log10(abs(x))))-1)
else:
return x
# Round, enough for laboratory work
def enoughRound(x):
return roundSig(x,3)
def studentCoefficient(data):
# Student coefficients for alpha=0.9 (from 2 to 11 experiments)
coefs = [2.92, 2.35, 2.13, 2.02, 1.94, 1.89, 1.86, 1.83, 1.81, 1.80]
infinityCoeff = 1.60
length = len(data)
if length >= 3:
if length < 13:
return coefs[length-3]
else:
return infinityCoeff
else:
raise RuntimeWarning("There aren't Student coefficient for {} experiments!".format(length))
return -1
# -------------------------------------------------------------
# Average value for experiments's data
# -------------------------------------------------------------
def averangeValueOf(data):
result = 0.0
for elem in data:
result += elem
result = result / len(data)
return enoughRound(result)
#-------------------------------------------------------------
# square average deviation value for experiments's data
#-------------------------------------------------------------
def meanSquareDeviationOf(data):
averange = averangeValueOf(data)
result = reduce(lambda acc, x: acc+((averange-x)**2), data, 0.0)
result = math.sqrt(result / len(data) / (len(data)-1))
return enoughRound(result)
#-------------------------------------------------------------
# Create calculation table
#-------------------------------------------------------------
def makeCalculationTable(data):
averange = averangeValueOf(data)
table = PrettyTable(['N', 'x', '|<x> - x_i|','(<x> - x_i)^2'])
for i,x in enumerate(data):
table.add_row([
i,
toFixedStr(x),
toFixedStr(abs(enoughRound(x-averange))),
toFixedStr(enoughRound((x-averange)**2))
])
squareDeviation = meanSquareDeviationOf(calcs)
return averange, squareDeviation, table
#-------------------------------------------------------------
# Check data for 'missings' and return all 'missing' value
#-------------------------------------------------------------
def missCheck(data):
averange = averangeValueOf(data)
squareDeviation = meanSquareDeviationOf(data)
# If |<x> - x_i| > 3 * S_<x> * sqrt(N) then x_i is 'missing'
missCheckFunc = lambda x: abs(averange - x) > 3 * squareDeviation * math.sqrt(len(data))
result = []
for i, x in enumerate(data):
if missCheckFunc(x):
result.append(i)
return result
#-------------------------------------------------------------
# Calculate random Error and relative Error
#-------------------------------------------------------------
def randomError(data):
return enoughRound(meanSquareDeviationOf(data)*studentCoefficient(data))
def relativeError(data):
# in percents
return round(randomError(data) / averangeValueOf(data) * 100, 1)
#-------------------------------------------------------------
# Main program body
#-------------------------------------------------------------
try:
calcs = list(map(float, sys.argv[1:]))
except ValueError as err:
print("One of input values isn't number. Correct a mistake")
print(err)
exit()
print("Input data")
print(calcs)
print("")
averange, deviation, table = makeCalculationTable(calcs)
print("<x> = {} у.е".format(averange))
print("S_<x> = {} у.е".format(deviation))
print("")
print("Calculation table")
print(table)
print("")
# Checking for 'missings'
missing = missCheck(calcs)
if len(missing) != 0:
print("'Missings' found")
table = PrettyTable(['№', 'x'])
for index in missing:
table.add_row([index+1, calcs[index]])
print(table)
print("")
# Remove found 'missings'
for index in missing:
del calcs[index]
averange, deviation, table = makeCalculationTable(calcs)
print("New <x> = {} у.е ".format(averange))
print("New S_<x> = {} у.е".format(deviation))
print("")
print("New calculation table")
print(table)
else:
print("Without 'missings'")
print("")
randErr = randomError(calcs)
print("Random error = {}".format(randErr))
print("")
relErr = relativeError(calcs)
if relErr < 10:
print("Relative error = {}%".format(relErr))
else:
print("Too big relative error ({}%)! Check your input data!".format(relErr))
print("")
averange = averangeValueOf(calcs)
print("Answer")
print("x = {} ± {} у.е".format(averange,randErr))
print("")
print("Confidence interval")
print("[{0}-{1}; {0}+{1}]".format(averange,randErr))