Программы на Python для вычисления статистики для лабораторных данных


Я новичок в Python, но у меня есть лабораторная работа с некоторых рутинных вычислений, поэтому я решила сделать все эти вычисления в Python.

Входные данные программы-это физическая характеристика, измеряемая в несколько раз (я.список электронных поплавков). Программа вычисляет среднее значение и среднее отклонение площади для списка. После этого, он делает таблицу промежуточных расчетов (мне нужно записать эту таблицу в лабораторной работе) и печатает его. Затем, используя квадрат среднего отклонения, программа проверяет данные, которые вызывают подозрения на погрешность измерения. Если существуют неправильные данные, программа удаляет его и пересчитать и перепечатать среднее значение, среднее квадратичное отклонение и таблицы. После этого программа вычисляет и печатает случайную и относительную погрешности измерения, а также выводит ответ.

Программа работает, но меня беспокоит его дизайн и структура.

  • Это обычная практика для программистов Python в первую очередь операторы импорта, то некоторые функции, а затем основной части программы? Есть ли более читаемым структура программного кода?
  • Многострочные комментарии (т. е. """ """ ) стандарт де-факто программирования Python или есть общие стандарты для многострочного комментирования?
  • Есть общий стиль кода на языке Python для замечаний функции?

Код:

#!/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))


233
8
задан 26 февраля 2018 в 07:02 Источник Поделиться
Комментарии
3 ответа

Ваши вопросы все ответили в Пеп-8 стиль руководства.


  • Да, импорт на первом месте.

  • Вы делаете "многострочные комментарии" правильно

  • Пеп-0257 очертания строкой документации функции конвенций - короче говоря, вы должны использовать """multi-line comment styled docstring""" внутри вашей функции декларации.

После приема быстро пройти через ваш код у меня есть некоторые дополнительные соображения (и личное мнение):


  1. Я чувствую, вы под-используя встроенные функции, такие как avg, mapи reduce. (missCheck было бы хорошее место, чтобы использовать map).

  2. Мне нравится верблюжьего (mixedCase ака), но Пеп-8 говорит, что имена функций и переменных должны быть lower_case_with_underscores.

  3. рассмотрите возможность использования лесозаготовки модуль , а не print.

  4. а не печатать сообщение об ошибке, а затем удалились, рассмотреть вопрос о повышении исключение (вы можете использовать один из встроенных исключений , если вы не хотите реализовать пользовательский).

7
ответ дан 27 февраля 2018 в 02:02 Источник Поделиться

постараюсь ответить на некоторые ваши опасения по поводу кода

Функция комментарии

Первыми выйдут на старт для функции комментарии. Как правило, вы хотели бы получить строкой документации (это раздел комментарий функция), которая описывает то, что делает функция, как она делает это (при необходимости) и информация о параметрах и возвращаемых значений

Применяя это к одной из ваших функций:

# Round only significant digits
def roundSig(x, sig=2):

Результат будет следующим

def roundSig(x, sig=2):
"""
Round only significant digits
:param x: number to round
:param sig: significant digits to use
:return: number after performing rounding
"""

Это будет большим подспорьем, когда кто-то приближается ваш код и понять, что ваша функция делает. Или когда у вас же в 3 месяца :)

Улучшение читаемости

То, что должно быть проблемой, когда ваша программа начнет расти, это, чтобы держать его читаемым. Для, за исключением ряда конвенций, которые @7yl4r упомянул, можно использовать небольшие уловки, которые помогут сделать код более понятным

Один из самых простых способов, чтобы улучшить читаемость точного именования. Если вы приближаетесь к функции roundSig(x, sig=2) это будет трудно понять, что он делает. Кроме того, в Python вы попробуйте написать функции с помощью подчеркивания отдельных слов по определению, поэтому первым шагом будет изменение наименования round_sig.

Но мы просто разминались

Давайте попробуем подумать, что эта функция делает: округление чисел. Он принимает два параметра: число и сколько значащих цифр, мы хотим учитывать. Этого должно быть достаточно средств, чтобы переписать функцию именования в что-то более разборчиво

def round_number(number, significant_digits=2):
"""
Rounds number using only significant_digits
...

Магия чисел

В программировании, иногда функция делает некоторые вычисления, а не другим, в зависимости от условия. Если это условие не выполняется ряд, который может показаться произвольным, если у вас нет знания о применении, можно сказать, это число волшебное

В ваш код, он появляется в некоторых функциях есть какая-то магия чисел, и принимаются решения, которые трудно понять, просто читая код

Взять этот пример в studentCoefficient(data):

length = len(data)
if length >= 3:
if length < 13:
...

Кажется, что цифры 3 и 13 есть, но нет понимания, как и почему они появляются, а не 20, или 100, или что там еще

Поэтому хорошо бы ввести это число в переменную, а затем использовать его для условной проверки. min_experiments = 3 и max_experiments = 13 может сработать, хотя вы можете выбрать лучшего именования

Лесозаготовки

Как было отмечено в предыдущем комментарии, было бы очень интересно использовать некоторые средства входа для вашей программы, поскольку вы можете не только выводить результаты в консоль, но в то же время сохранить их в файл для дальнейшей проверки

Организации код

Если вы планируете запускать программы в качестве сценария, можно включить в главном предложении в тексте файла, где вы будете группой его выполнение вместе. Который в данном случае является все, что происходит ниже Main program body комментарий.

Немного подробнее об этом здесь https://stackoverflow.com/questions/419163/what-does-if-name-main-do

Как только вы закончите с ним, вы откроете для себя количество вещей, происходящих в организме огромна, так что будет интересно, чтобы извлечь ее части на более мелкие функции, и лучше отдельной функции обслуживания.

Например, все, что происходит ниже # Checking for 'missings' могут быть извлечены в функцию check_for_missings(calcs) или что-то с лучшим имен можно придумать

В общем есть много места для улучшений, поэтому я призываю вас, чтобы следить за комментариями и стараемся работать на ваш код немного больше

Наслаждайтесь кодирования! :)

7
ответ дан 27 февраля 2018 в 04:02 Источник Поделиться

Если вы делаете много численные вычисления на языке Python (и делают статистику наверняка считается это), вы, вероятно, следует узнать о numpy. это модуль Python, который реализует массивы и быстро векторизовать операции над ними.

Вы можете преобразовать в список (или на самом деле, любой итерируемый) к numpy массив с:

import numpy as np
data = np.array([1,2,0.5])

Ваши две функции статистики намного проще реализовать:

def average(data):
return data.mean()

def mean_square_deviation(data):
mu = data.mean()
result = ((data - mu)**2).sum()
return enough_round(np.sqrt(result) / len(data))

Обратите внимание, что вы обычно используете либо \$1/П\$ и \$1/(П-1)\$, а не смесь между двумя. Отметим также, что это на самом деле не означать площади (так как вы берете квадратный корень потом). Это на самом деле просто стандартное отклонение, которое вы можете сделать с:

def std(data):
return data.std()

4
ответ дан 28 февраля 2018 в 11:02 Источник Поделиться