13 Commits

Author SHA1 Message Date
github-actions[bot]
7cbb93e37c chore(main): release 0.9.0 (#93)
🤖 I have created a release *beep* *boop*
---


## [0.9.0](https://github.com/shizand/statapp/compare/v0.8.0...v0.9.0)
(2024-01-02)


### Новые функции

* добавлен "Прогноз"
([#92](https://github.com/shizand/statapp/issues/92))
([8ea3cff](8ea3cffa7e)),
closes [#85](https://github.com/shizand/statapp/issues/85)

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-01-02 17:29:45 +03:00
8ea3cffa7e feat: добавлен "Прогноз" (#92)
Closes #85
2024-01-02 17:22:59 +03:00
github-actions[bot]
51fc413fca chore(main): release 0.8.0 (#91)
🤖 I have created a release *beep* *boop*
---


## [0.8.0](https://github.com/shizand/statapp/compare/v0.7.0...v0.8.0)
(2023-12-31)


### Новые функции

* добавлены преобразования
([#90](https://github.com/shizand/statapp/issues/90))
([f70be43](f70be431cf))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-12-31 10:17:56 +03:00
f70be431cf feat: добавлены преобразования (#90)
Closes #41

---------

Co-authored-by: MisterMLiL <eugenelazurenko@gmail.com>
2023-12-31 10:12:01 +03:00
github-actions[bot]
4f1f610822 chore(main): release 0.7.0 (#88)
🤖 I have created a release *beep* *boop*
---


## [0.7.0](https://github.com/shizand/statapp/compare/v0.6.0...v0.7.0)
(2023-12-01)


### Новые функции

* добавлена возможность ввода чисел до 5 знаков
([#87](https://github.com/shizand/statapp/issues/87))
([dc7c487](dc7c4875d7)),
closes [#82](https://github.com/shizand/statapp/issues/82)
* Добавлены новые характеристики
([#89](https://github.com/shizand/statapp/issues/89))
([b12db5a](b12db5a300)),
closes [#84](https://github.com/shizand/statapp/issues/84)

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-12-01 14:11:49 +03:00
b12db5a300 feat: Добавлены новые характеристики (#89)
Closes #84
2023-12-01 14:03:20 +03:00
dc7c4875d7 feat: добавлена возможность ввода чисел до 5 знаков (#87)
Closes #82
2023-11-25 14:21:05 +03:00
2f5988a2eb chore: исправляет форматирование 2023-10-25 17:11:09 +03:00
9348138094 chore: исправляет описание в "Установка" 2023-10-25 17:09:30 +03:00
c35b9ca308 chore: исправляет опечатки 2023-10-25 15:58:06 +03:00
e6ba0fc610 ci: Revert "добавил сборку linux x86"
This reverts commit 4be89269b9.
2023-10-20 14:46:57 +03:00
cddacb21b2 Merge remote-tracking branch 'origin/main' 2023-10-20 14:20:27 +03:00
4be89269b9 ci: добавил сборку linux x86 2023-10-20 14:20:12 +03:00
34 changed files with 794 additions and 357 deletions

2
.idea/misc.xml generated
View File

@@ -3,5 +3,5 @@
<component name="Black"> <component name="Black">
<option name="sdkName" value="Poetry (statapp)" /> <option name="sdkName" value="Poetry (statapp)" />
</component> </component>
<component name="ProjectRootManager" version="2" project-jdk-name="Poetry (statapp)" project-jdk-type="Python SDK" /> <component name="ProjectRootManager" version="2" project-jdk-name="statapp" project-jdk-type="Python SDK" />
</project> </project>

View File

@@ -1,15 +1,15 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="statapp" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true"> <configuration default="false" name="statapp" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
<module name="stat" /> <module name="stat" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" /> <option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" /> <option name="PARENT_ENVS" value="true" />
<envs> <envs>
<env name="PYTHONUNBUFFERED" value="1" /> <env name="PYTHONUNBUFFERED" value="1" />
</envs> </envs>
<option name="SDK_HOME" value="" /> <option name="SDK_HOME" value="" />
<option name="SDK_NAME" value="Poetry (statapp)" />
<option name="WORKING_DIRECTORY" value="" /> <option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="false" /> <option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" /> <option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" /> <option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="statapp" /> <option name="SCRIPT_NAME" value="statapp" />

2
.idea/stat.iml generated
View File

@@ -2,7 +2,7 @@
<module type="PYTHON_MODULE" version="4"> <module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager"> <component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Poetry (statapp)" jdkType="Python SDK" /> <orderEntry type="jdk" jdkName="statapp" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
</module> </module>

View File

@@ -1,5 +1,27 @@
# Changelog # Changelog
## [0.9.0](https://github.com/shizand/statapp/compare/v0.8.0...v0.9.0) (2024-01-02)
### Новые функции
* добавлен "Прогноз" ([#92](https://github.com/shizand/statapp/issues/92)) ([8ea3cff](https://github.com/shizand/statapp/commit/8ea3cffa7e0d920141c8eda71952ff02d2c02905)), closes [#85](https://github.com/shizand/statapp/issues/85)
## [0.8.0](https://github.com/shizand/statapp/compare/v0.7.0...v0.8.0) (2023-12-31)
### Новые функции
* добавлены преобразования ([#90](https://github.com/shizand/statapp/issues/90)) ([f70be43](https://github.com/shizand/statapp/commit/f70be431cfb4ecda5c3e706f4ca95171bbe779b3))
## [0.7.0](https://github.com/shizand/statapp/compare/v0.6.0...v0.7.0) (2023-12-01)
### Новые функции
* добавлена возможность ввода чисел до 5 знаков ([#87](https://github.com/shizand/statapp/issues/87)) ([dc7c487](https://github.com/shizand/statapp/commit/dc7c4875d7e15ad8c9ae5fa16b4b589d156632dd)), closes [#82](https://github.com/shizand/statapp/issues/82)
* Добавлены новые характеристики ([#89](https://github.com/shizand/statapp/issues/89)) ([b12db5a](https://github.com/shizand/statapp/commit/b12db5a3003802830784e26a14097ee9d68a0e64)), closes [#84](https://github.com/shizand/statapp/issues/84)
## [0.6.0](https://github.com/shizand/statapp/compare/v0.5.0...v0.6.0) (2023-10-20) ## [0.6.0](https://github.com/shizand/statapp/compare/v0.5.0...v0.6.0) (2023-10-20)

View File

@@ -5,13 +5,13 @@
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/c4e370d74a8a4575b79afa8b9b74d130)](https://app.codacy.com/gh/shizand/statapp/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/c4e370d74a8a4575b79afa8b9b74d130)](https://app.codacy.com/gh/shizand/statapp/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
![License info](https://img.shields.io/github/license/shizand/statapp) ![License info](https://img.shields.io/github/license/shizand/statapp)
Автоматизированное программное средство по статистическому анализу и регрессионному моделированию. Является идейным продолжателем программы STAT.exe (Produced by Reutov V.N., Donetsk University, 1990) Автоматизированное программное средство по статистическому анализу и регрессионному моделированию. Является идейным продолжателем программы STAT.exe (Produced by Reutov V.N., Donetsk University, 1990).
Разработано двумя студентами ФГБОУ ВО «ДонНТУ» для своего университета. Разработано двумя студентами ФГБОУ ВО «ДонНТУ» для своего университета.
## Поддерживаемые ОС и архитектуры ## Поддерживаемые ОС и архитектуры
В теории, должно работать на любой архитектуре и ОС где запускается Python 3.8 и есть Qt 5. В теории, должно работать на любой архитектуре и ОС, где запускается Python 3.8 и есть Qt 5.
Работоспособность проверена на x64: Работоспособность проверена на x64:
@@ -20,7 +20,11 @@
## Установка ## Установка
Существует два варианта statapp и statapp-onefile. Различия в том, что onefile версия поставляется одним единственным бинарным файлом. На Windows системах с включенным антивирусом это может вызывать [некоторые проблемы](https://qna.habr.com/q/988553). Программа распространяется с помощью [PyInstaller](https://pyinstaller.org/en/stable/).
Существует две версиии: **statapp** и **statapp-onefile**.
Различия в том, что onefile версия поставляется одним единственным бинарным файлом. На Windows системах с включенным антивирусом это может вызывать [некоторые проблемы](https://qna.habr.com/q/988553).
### Готовые двоичные файлы ### Готовые двоичные файлы

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "statapp" name = "statapp"
version = "0.6.0" version = "0.9.0"
description = "" description = ""
authors = [ authors = [
"Maxim Slipenko <statapp@maks1ms.addy.io>" "Maxim Slipenko <statapp@maks1ms.addy.io>"

View File

@@ -39,5 +39,6 @@ def main():
window.show() window.show()
return app.exec_() return app.exec_()
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(main()) sys.exit(main())

View File

@@ -9,8 +9,7 @@
# See the GPL-3.0 license for details. # See the GPL-3.0 license for details.
import itertools import itertools
import numpy as np from numpy import linalg, zeros, ones, hstack, asarray
from numpy import linalg, zeros, ones, hstack, asarray, diagonal
from sympy import symbols, Mul, Add, S from sympy import symbols, Mul, Add, S
@@ -90,15 +89,7 @@ def multipolyfit(xs, y, deg, full=False, modelOut=False, powersOut=False):
return beta, powers return beta, powers
if full: if full:
residues = result[1] return result, powers, a
dof = len(a) - len(beta)
mse = residues / dof
cov = mse * diagonal(linalg.inv(a.T @ a))
se = np.sqrt(cov)
tStatistics = beta / se
return result, powers, tStatistics, mse
return beta return beta

View File

@@ -21,6 +21,7 @@ from dataclasses import dataclass
import numpy as np import numpy as np
import pandas as pd import pandas as pd
import sympy as sp
from statapp._vendor.multipolyfit import multipolyfit, getTerms from statapp._vendor.multipolyfit import multipolyfit, getTerms
DIRECT_LINK = 0 DIRECT_LINK = 0
@@ -66,54 +67,108 @@ class RegressionResult:
Attributes: Attributes:
paramsAndImportance (np.ndarray): Параметры модели. Первая колонка - paramsAndImportance (np.ndarray): Параметры модели. Первая колонка -
residualVariance (np.float64): Остаточная дисперсия residualVariance (np.float64): Остаточная дисперсия
scaledResidualVariance (np.float64): Остаточная дисперсия (масштабированная)
monomials (list): Список одночленов в строковом виде без коэффициентов. Свободный член - c monomials (list): Список одночленов в строковом виде без коэффициентов. Свободный член - c
""" """
paramsAndImportance: np.ndarray paramsAndImportance: np.ndarray
residualVariance: np.float64 residualVariance: np.float64
scaledResidualVariance: np.float64
rSquared: np.float64
fStatistic: np.float64
monomials: list monomials: list
def linearPolynom(inputData) -> RegressionResult: def commonPolynom(inputData, deg) -> RegressionResult:
x = inputData[:, 1:] x = inputData[:, 1:]
y = inputData[:, 0] y = inputData[:, 0]
data = pd.DataFrame(x) result, powers, data = multipolyfit(x, y, deg, full=True)
data.insert(0, 'const', 1) (out, mse, scaledResidualVariance,
# --- rSquared, fStatistic) = calculateStats(data, result[0], result[1], y)
result = np.linalg.lstsq(data, y, rcond=None)
# Коэффициенты регрессии return RegressionResult(
params = result[0] out.to_numpy(),
# Остатки np.float64(mse),
residues = result[1] np.float64(scaledResidualVariance),
dof = len(data) - len(params) np.float64(rSquared),
np.float64(fStatistic),
['c' if str(x) == '1' else str(x) for x in getTerms(powers)]
)
def linearPolynom(inputData) -> RegressionResult:
return commonPolynom(inputData, 1)
def squaredPolynom(inputData) -> RegressionResult:
return commonPolynom(inputData, 2)
def calculateStats(data, params, residues, y):
# pylint: disable-msg=too-many-locals
k = len(params) # Количество оцениваемых параметров (коэффициентов)
n = len(data) # Количество наблюдений
# Степень свободы (degrees of freedom) для остатков
dof = n - k # Количество наблюдений минус количество оцениваемых параметров
# Остаточная дисперсия (Mean Squared Error, MSE)
mse = residues / dof mse = residues / dof
# Среднее значение остатков
meanResiduals = np.sum(residues) / dof
# Масштабированная остаточная дисперсия
scaledResidualVariance = residues / meanResiduals ** 2
# Ковариационная матрица коэффициентов
cov = mse * np.diagonal(np.linalg.inv(data.T @ data)) cov = mse * np.diagonal(np.linalg.inv(data.T @ data))
# Стандартные ошибки коэффициентов
se = np.sqrt(cov) se = np.sqrt(cov)
# T-статистики для каждого коэффициента регрессии
tStatistics = params / se tStatistics = params / se
# возможно стоит сделать через np.reshape + np.concatenate # R-squared (коэффициент множественной детерминации)
sst = np.sum((y - np.mean(y)) ** 2) # Сумма квадратов отклонений
rSquared = 1 - (mse[0] / sst)
# F-statistic (статистика Фишера)
fStatistic = (rSquared / (k - 1)) / ((1 - rSquared) / (n - k))
out = pd.DataFrame() out = pd.DataFrame()
out[0] = params out[0] = params
out[1] = tStatistics out[1] = tStatistics
return RegressionResult( return out, mse[0], scaledResidualVariance, rSquared, fStatistic
out.to_numpy(),
np.float64(mse[0]),
['c'] + [f'x{i}' for i in range(1, len(params))]
)
def squaredPolynom(inputData): def prediction(inputData, result: RegressionResult):
x = inputData[:, 1:] inputs = inputData[:, 1:]
y = inputData[:, 0] outputs = inputData[:, 0]
result, powers, tStatistics, mse = multipolyfit(x, y, 2, full=True)
betas = result[0]
out = pd.DataFrame() params = result.paramsAndImportance[:, 0]
out[0] = betas
out[1] = tStatistics
return RegressionResult( expr = sp.sympify(' '.join(
out.to_numpy(), [
np.float64(mse[0]), f'{param}' if m == 'c' else f' + ({param}) * {m}'
['c' if str(x) == '1' else str(x) for x in getTerms(powers)] for param, m in zip(params, result.monomials)
) ]
))
results = []
for y, xValues in zip(outputs, inputs):
subsDict = dict(zip(expr.free_symbols, xValues))
predictedResult = expr.subs(subsDict)
difference = predictedResult - y
results.append([y, predictedResult, difference, 0.0])
results = np.array(results, dtype=np.float32)
# Расчет среднего значения и стандартного отклонения разностей
meanDifference = np.mean(results[:, 2])
stdDifference = np.std(results[:, 2])
# Установка флага 1.0, если разность выходит за пределы 3 стандартных отклонений
for row in results:
if abs(row[2] - meanDifference) > 3 * stdDifference:
row[3] = 1.0
return results

63
statapp/combo_delegate.py Normal file
View File

@@ -0,0 +1,63 @@
#
# Copyright (c) 2023 Maxim Slipenko, Eugene Lazurenko.
#
# This file is part of Statapp
# (see https://github.com/shizand/statapp).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from PySide2 import QtCore
from PySide2.QtWidgets import QComboBox, QItemDelegate
class ComboDelegate(QItemDelegate):
commitData = QtCore.Signal(object)
"""
A delegate that places a fully functioning QComboBox in every
cell of the column to which it's applied
"""
def __init__(self, parent, objects, objectNames):
"""
Constructoe
:param parent: QTableView parent object
:param objects: List of objects to set. i.e. [True, False]
:param objectNames: List of Object names to display. i.e. ['True', 'False']
"""
QItemDelegate.__init__(self, parent)
# objects to sent to the model associated to the combobox. i.e. [True, False]
self.objects = objects
# object description to display in the combobox. i.e. ['True', 'False']
self.objectNames = objectNames
@QtCore.Slot()
def currentIndexChanged(self):
self.commitData.emit(self.sender())
def createEditor(self, parent, option, index):
combo = QComboBox(parent)
combo.addItems(self.objectNames)
combo.currentIndexChanged.connect(self.currentIndexChanged)
return combo
def setEditorData(self, editor, index):
editor.blockSignals(True)
val = index.model().data(index, role=QtCore.Qt.DisplayRole)
idx = self.objects.index(val)
editor.setCurrentIndex(idx)
editor.blockSignals(False)
def setModelData(self, editor, model, index):
model.setData(index, self.objects[editor.currentIndex()], QtCore.Qt.EditRole)

20
statapp/constants.py Normal file
View File

@@ -0,0 +1,20 @@
#
# Copyright (c) 2023 Maxim Slipenko, Eugene Lazurenko.
#
# This file is part of Statapp
# (see https://github.com/shizand/statapp).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
NUMBERS_PRECISION = 5

View File

@@ -23,6 +23,7 @@ from PySide2.QtGui import QIcon
from PySide2.QtWidgets import QDialog, QHeaderView from PySide2.QtWidgets import QDialog, QHeaderView
from statapp.calculations import correlationAnalysis from statapp.calculations import correlationAnalysis
from statapp.constants import NUMBERS_PRECISION
from statapp.mathtex_header_view import MathTexHeaderView from statapp.mathtex_header_view import MathTexHeaderView
from statapp.models.correlation_analysis_model import CorrelationAnalysisModel from statapp.models.correlation_analysis_model import CorrelationAnalysisModel
from statapp.ui.ui_correlation_analysis_window import Ui_CorrelationAnalysisWindow from statapp.ui.ui_correlation_analysis_window import Ui_CorrelationAnalysisWindow
@@ -36,7 +37,7 @@ class CorrelationAnalysisWindow(QDialog):
self.ui.setupUi(self) self.ui.setupUi(self)
res = correlationAnalysis(data) res = correlationAnalysis(data)
self.model = CorrelationAnalysisModel(res.round(2)) self.model = CorrelationAnalysisModel(res.round(NUMBERS_PRECISION))
self.ui.tableView.setModel(self.model) self.ui.tableView.setModel(self.model)
self.ui.tableView.setVerticalHeader( self.ui.tableView.setVerticalHeader(
MathTexHeaderView(self.ui.tableView) MathTexHeaderView(self.ui.tableView)

View File

@@ -23,18 +23,20 @@ from PySide2.QtCore import Slot
from PySide2.QtWidgets import QMainWindow, QMessageBox from PySide2.QtWidgets import QMainWindow, QMessageBox
from statapp.calculations import generateXValues, generateYValues from statapp.calculations import generateXValues, generateYValues
from statapp.constants import NUMBERS_PRECISION
from statapp.generate_factor_window import GenerateFactorWindow from statapp.generate_factor_window import GenerateFactorWindow
from statapp.linear_polynom_window import LinearPolynomWindow from statapp.polynoms.linear_polynom_window import LinearPolynomWindow
from statapp.mathtex_header_view import MathTexHeaderView from statapp.mathtex_header_view import MathTexHeaderView
from statapp.models.input_values_model import InputValuesModel from statapp.models.input_values_model import InputValuesModel
from statapp.generate_window import GenerateWindow from statapp.generate_window import GenerateWindow
from statapp.about_window import AboutWindow from statapp.about_window import AboutWindow
from statapp.models.fileslc_model import FileSLCModel from statapp.models.fileslc_model import FileSLCModel
from statapp.squared_polynom_window import SquaredPolynomWindow from statapp.polynoms.squared_polynom_window import SquaredPolynomWindow
from statapp.ui.ui_main_window import Ui_MainWindow from statapp.ui.ui_main_window import Ui_MainWindow
from statapp.utils import buildMessageBox, addIcon from statapp.utils import buildMessageBox, addIcon, FloatDelegate
from statapp.variance_analysis import VarianceAnalysisWindow from statapp.variance_analysis import VarianceAnalysisWindow
from statapp.correlation_analysis import CorrelationAnalysisWindow from statapp.correlation_analysis import CorrelationAnalysisWindow
from statapp.polynoms.transform_polynom_window import TransformPolynomWindow
class MainWindow(QMainWindow): class MainWindow(QMainWindow):
@@ -55,6 +57,7 @@ class MainWindow(QMainWindow):
self.ui.correlationAnalisisAction, self.ui.correlationAnalisisAction,
self.ui.linearPolynomAction, self.ui.linearPolynomAction,
self.ui.squaredPolynomAction, self.ui.squaredPolynomAction,
self.ui.transformPolynomAction,
] ]
self.aboutWindow = None self.aboutWindow = None
@@ -62,6 +65,7 @@ class MainWindow(QMainWindow):
self.isDataChanged = False self.isDataChanged = False
self.model = InputValuesModel() self.model = InputValuesModel()
self.fileModel = FileSLCModel() self.fileModel = FileSLCModel()
self.ui.tableView.setItemDelegate(FloatDelegate())
self.ui.tableView.setModel(self.model) self.ui.tableView.setModel(self.model)
self.ui.tableView.setHorizontalHeader( self.ui.tableView.setHorizontalHeader(
MathTexHeaderView(self.ui.tableView, orientation=QtCore.Qt.Horizontal) MathTexHeaderView(self.ui.tableView, orientation=QtCore.Qt.Horizontal)
@@ -150,7 +154,7 @@ class MainWindow(QMainWindow):
if gw.exec(): if gw.exec():
y = generateYValues(gw.mat, gw.deviation, gw.count) y = generateYValues(gw.mat, gw.deviation, gw.count)
self.model.updateAllData(y.round(2)) self.model.updateAllData(y.round(NUMBERS_PRECISION))
self.isDataChanged = True self.isDataChanged = True
@Slot() @Slot()
@@ -161,7 +165,7 @@ class MainWindow(QMainWindow):
data = self.model.getData() data = self.model.getData()
y = self.model.getY() y = self.model.getY()
xValues = generateXValues(gfw.mat, gfw.deviation, gfw.typeConnection, y) xValues = generateXValues(gfw.mat, gfw.deviation, gfw.typeConnection, y)
data = np.concatenate((data, xValues.round(2)), axis=1) data = np.concatenate((data, xValues.round(NUMBERS_PRECISION)), axis=1)
self.model.updateAllData(data) self.model.updateAllData(data)
self.isDataChanged = True self.isDataChanged = True
@@ -190,6 +194,11 @@ class MainWindow(QMainWindow):
dw = SquaredPolynomWindow(self.model.getData()) dw = SquaredPolynomWindow(self.model.getData())
dw.exec() dw.exec()
@Slot()
def on_transformPolynomAction_triggered(self):
dw = TransformPolynomWindow(self.model.getData())
dw.exec()
def closeEvent(self, event): def closeEvent(self, event):
if self.isDataChanged: if self.isDataChanged:
file = '' file = ''

View File

@@ -20,6 +20,7 @@
import numpy as np import numpy as np
from PySide2.QtWidgets import QFileDialog, QMessageBox from PySide2.QtWidgets import QFileDialog, QMessageBox
from statapp.constants import NUMBERS_PRECISION
from statapp.utils import buildMessageBox from statapp.utils import buildMessageBox
@@ -57,7 +58,7 @@ class FileSLCModel:
None, "Сохранить файл", "", "Text Files (*.txt);;CSV Files (*.csv)" None, "Сохранить файл", "", "Text Files (*.txt);;CSV Files (*.csv)"
) )
if self.fileName: if self.fileName:
np.savetxt(self.fileName, data, delimiter=",", fmt='%10.5f') np.savetxt(self.fileName, data, delimiter=",", fmt=f"%.{NUMBERS_PRECISION}f")
return True return True
return False return False

View File

@@ -0,0 +1,33 @@
#
# Copyright (c) 2023 Maxim Slipenko, Eugene Lazurenko.
#
# This file is part of Statapp
# (see https://github.com/shizand/statapp).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from PySide2.QtCore import Qt
from statapp.models.ro_table_model import ROTableModel
class PreditionTableModel(ROTableModel):
def getHorizontalHeader(self):
return ['Отклик', 'Прогноз', 'Отклонение', '1-3 сигмовые зоны']
def data(self, index, role):
if role == Qt.DisplayRole and index.column() == 3:
value = super().data(index, role)
return 'x' if value == 1 else ''
return super().data(index, role)

View File

@@ -0,0 +1,74 @@
#
# Copyright (c) 2023 Maxim Slipenko, Eugene Lazurenko.
#
# This file is part of Statapp
# (see https://github.com/shizand/statapp).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import numpy as np
from PySide2.QtCore import Qt
from statapp.models.editable_table_model import EditableTableModel
from statapp.models.regression_result_model import RegressionResultModel
def defaultX(x):
return x
TRANSFORMS = {
'-': defaultX,
'sin(x)': np.sin,
'cos(x)': np.cos,
'log(x)': np.log,
'exp(x)': np.exp,
}
class TransformPolynomModel(RegressionResultModel, EditableTableModel):
def __init__(self, result):
self._monomials = None
super().__init__(result)
n = result.paramsAndImportance.shape[0]
self._transforms = ['-'] * n
def columnCount(self, index):
return 3
def updateAllData(self, data):
d = data.paramsAndImportance
self._monomials = data.monomials
super().updateAllData(d)
def flags(self, index):
if index.column() == 0 and index.row() != 0:
return EditableTableModel.flags(self, index)
return RegressionResultModel.flags(self, index)
def data(self, index, role):
if role == Qt.DisplayRole and index.column() == 0:
return self._transforms[index.row()]
return super().data(index, role)
def setData(self, index, value, role):
if role == Qt.EditRole and index.column() == 0:
self._transforms[index.row()] = value
topLeftIndex = self.createIndex(index.row(), 0)
bottomRightIndex = self.createIndex(index.row(), 0)
self.dataChanged.emit(topLeftIndex, bottomRightIndex)
return True
return super().setData(index, value, role)
def getHorizontalHeader(self):
return ['Преобразования'] + super().getHorizontalHeader()

View File

@@ -0,0 +1,27 @@
#
# Copyright (c) 2023 Maxim Slipenko, Eugene Lazurenko.
#
# This file is part of Statapp
# (see https://github.com/shizand/statapp).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from statapp.calculations import linearPolynom
from statapp.polynoms.polynom_window import PolynomWindow
class LinearPolynomWindow(PolynomWindow):
def __init__(self, data):
result = linearPolynom(data)
super().__init__(data, result, "Линейный полином")

View File

@@ -19,26 +19,35 @@
# #
from PySide2.QtWidgets import QDialog, QHeaderView from PySide2.QtWidgets import QDialog, QHeaderView
from statapp.calculations import linearPolynom from statapp.calculations import prediction
from statapp.mathtex_header_view import MathTexHeaderView from statapp.mathtex_header_view import MathTexHeaderView
from statapp.models.prediction_table_model import PreditionTableModel
from statapp.models.regression_result_model import RegressionResultModel from statapp.models.regression_result_model import RegressionResultModel
from statapp.ui.ui_linear_polynom_window import Ui_LinearPolynomWindow from statapp.ui.ui_polynom_window import Ui_PolynomWindow
from statapp.utils import addIcon from statapp.utils import addIcon, FloatDelegate
class LinearPolynomWindow(QDialog): class PolynomWindow(QDialog):
def __init__(self, data): def __init__(self, data, result, windowTitle):
super().__init__() super().__init__()
self.ui = Ui_LinearPolynomWindow() self.ui = Ui_PolynomWindow()
self.ui.setupUi(self) self.ui.setupUi(self)
addIcon(self) addIcon(self)
self.setWindowTitle(windowTitle)
result = linearPolynom(data)
self.model = RegressionResultModel(result) self.model = RegressionResultModel(result)
self.ui.tableView.setItemDelegate(FloatDelegate())
self.ui.tableView.setModel(self.model) self.ui.tableView.setModel(self.model)
self.ui.tableView.setVerticalHeader(MathTexHeaderView(self.ui.tableView)) self.ui.tableView.setVerticalHeader(MathTexHeaderView(self.ui.tableView))
header = self.ui.tableView.horizontalHeader() header = self.ui.tableView.horizontalHeader()
header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch) header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
self.ui.residualVarianceValueLabel.setText(str(result.residualVariance)) self.ui.residualVarianceValueLabel.setText(str(result.residualVariance))
self.ui.scaledResidualVarianceValueLabel.setText(str(result.scaledResidualVariance))
self.ui.fStatisticValueLabel.setText(str(result.fStatistic))
self.ui.rSquaredValueLabel.setText(str(result.scaledResidualVariance))
self.predictionModel = PreditionTableModel(prediction(data, result))
self.ui.predictionTableView.setModel(self.predictionModel)
header = self.ui.predictionTableView.horizontalHeader()
header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch)

View File

@@ -17,28 +17,11 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from PySide2.QtWidgets import QDialog, QHeaderView
from statapp.calculations import squaredPolynom from statapp.calculations import squaredPolynom
from statapp.mathtex_header_view import MathTexHeaderView from statapp.polynoms.polynom_window import PolynomWindow
from statapp.models.regression_result_model import RegressionResultModel
from statapp.ui.ui_squared_polynom_window import Ui_SquaredPolynomWindow
from statapp.utils import addIcon
class SquaredPolynomWindow(QDialog): class SquaredPolynomWindow(PolynomWindow):
def __init__(self, data): def __init__(self, data):
super().__init__()
self.ui = Ui_SquaredPolynomWindow()
self.ui.setupUi(self)
addIcon(self)
result = squaredPolynom(data) result = squaredPolynom(data)
super().__init__(data, result, "Квадратичный полином")
self.model = RegressionResultModel(result)
self.ui.tableView.setModel(self.model)
self.ui.tableView.setVerticalHeader(MathTexHeaderView(self.ui.tableView))
header = self.ui.tableView.horizontalHeader()
header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
self.ui.residualVarianceValueLabel.setText(str(result.residualVariance))

View File

@@ -0,0 +1,94 @@
#
# Copyright (c) 2023 Maxim Slipenko, Eugene Lazurenko.
#
# This file is part of Statapp
# (see https://github.com/shizand/statapp).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import numpy as np
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QDialog, QHeaderView
from statapp.calculations import linearPolynom, prediction
from statapp.combo_delegate import ComboDelegate
from statapp.mathtex_header_view import MathTexHeaderView
from statapp.models.prediction_table_model import PreditionTableModel
from statapp.models.transform_polynom_model import TransformPolynomModel, TRANSFORMS
from statapp.ui.ui_polynom_window import Ui_PolynomWindow
from statapp.utils import addIcon
class TransformPolynomWindow(QDialog):
def __init__(self, data):
super().__init__()
self.ui = Ui_PolynomWindow()
self.ui.setupUi(self)
addIcon(self)
self.setWindowTitle("Преобразования")
self.data = data
result = linearPolynom(data)
self.predictionModel = PreditionTableModel(prediction(data, result))
self.ui.predictionTableView.setModel(self.predictionModel)
header = self.ui.predictionTableView.horizontalHeader()
header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
# Создание столбца из нулей
zeroCol = np.zeros((result.paramsAndImportance.shape[0], 1))
# Добавление столбца к исходному массиву
result.paramsAndImportance = np.column_stack((zeroCol, result.paramsAndImportance))
# self.ui.tableView.setItemDelegate(FloatDelegate())
self.ui.tableView.setItemDelegate(
ComboDelegate(
self.ui.tableView,
list(TRANSFORMS.keys()),
list(TRANSFORMS.keys()),
)
)
self.model = TransformPolynomModel(result)
self.ui.tableView.setModel(self.model)
self.ui.tableView.setVerticalHeader(MathTexHeaderView(self.ui.tableView))
header = self.ui.tableView.horizontalHeader()
header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
self.ui.residualVarianceValueLabel.setText(str(result.residualVariance))
self.ui.scaledResidualVarianceValueLabel.setText(str(result.scaledResidualVariance))
self.ui.fStatisticValueLabel.setText(str(result.fStatistic))
self.ui.rSquaredValueLabel.setText(str(result.scaledResidualVariance))
self.model.dataChanged.connect(self.on_data_changed)
def on_data_changed(self):
data = np.copy(self.data)
print(len(data[0:]))
for i in range(len(data[0:])):
for j in range(1, len(data[i])):
tr = self.model.data(self.model.createIndex(j, 0), Qt.DisplayRole)
data[i][j] = TRANSFORMS[tr](data[i][j])
self.rebuildData(data)
def rebuildData(self, data):
result = linearPolynom(data)
self.predictionModel.updateAllData(prediction(data, result))
zeroCol = np.zeros((result.paramsAndImportance.shape[0], 1))
result.paramsAndImportance = np.column_stack((zeroCol, result.paramsAndImportance))
self.model.updateAllData(result)
self.ui.residualVarianceValueLabel.setText(str(result.residualVariance))
self.ui.scaledResidualVarianceValueLabel.setText(str(result.scaledResidualVariance))
self.ui.fStatisticValueLabel.setText(str(result.fStatistic))
self.ui.rSquaredValueLabel.setText(str(result.scaledResidualVariance))

View File

@@ -71,6 +71,9 @@
<pointsize>12</pointsize> <pointsize>12</pointsize>
</font> </font>
</property> </property>
<property name="decimals">
<number>5</number>
</property>
<property name="maximum"> <property name="maximum">
<double>1000000.000000000000000</double> <double>1000000.000000000000000</double>
</property> </property>
@@ -83,6 +86,9 @@
<pointsize>12</pointsize> <pointsize>12</pointsize>
</font> </font>
</property> </property>
<property name="decimals">
<number>5</number>
</property>
<property name="maximum"> <property name="maximum">
<double>1000000.000000000000000</double> <double>1000000.000000000000000</double>
</property> </property>

View File

@@ -44,6 +44,9 @@
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QDoubleSpinBox" name="matSpinBox"> <widget class="QDoubleSpinBox" name="matSpinBox">
<property name="decimals">
<number>5</number>
</property>
<property name="maximum"> <property name="maximum">
<double>1000000.000000000000000</double> <double>1000000.000000000000000</double>
</property> </property>
@@ -68,6 +71,9 @@
</item> </item>
<item row="2" column="1"> <item row="2" column="1">
<widget class="QDoubleSpinBox" name="deviationSpinBox"> <widget class="QDoubleSpinBox" name="deviationSpinBox">
<property name="decimals">
<number>5</number>
</property>
<property name="maximum"> <property name="maximum">
<double>1000000.000000000000000</double> <double>1000000.000000000000000</double>
</property> </property>

View File

@@ -1,59 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LinearPolynomWindow</class>
<widget class="QDialog" name="LinearPolynomWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>630</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string>Линейный полином</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTableView" name="tableView">
<attribute name="horizontalHeaderMinimumSectionSize">
<number>40</number>
</attribute>
<attribute name="verticalHeaderMinimumSectionSize">
<number>40</number>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>40</number>
</attribute>
</widget>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout_3">
<property name="topMargin">
<number>10</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="residualVarianceLabel">
<property name="text">
<string>Остаточная дисперсия:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="residualVarianceValueLabel">
<property name="text">
<string>undefined</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -40,7 +40,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>800</width> <width>800</width>
<height>27</height> <height>21</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="filemenu"> <widget class="QMenu" name="filemenu">
@@ -71,6 +71,7 @@
</property> </property>
<addaction name="linearPolynomAction"/> <addaction name="linearPolynomAction"/>
<addaction name="squaredPolynomAction"/> <addaction name="squaredPolynomAction"/>
<addaction name="transformPolynomAction"/>
</widget> </widget>
<widget class="QMenu" name="helpmenu"> <widget class="QMenu" name="helpmenu">
<property name="title"> <property name="title">
@@ -135,6 +136,11 @@
<string>Квадратичный полином</string> <string>Квадратичный полином</string>
</property> </property>
</action> </action>
<action name="transformPolynomAction">
<property name="text">
<string>Преобразования</string>
</property>
</action>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections/>

View File

@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PolynomWindow</class>
<widget class="QDialog" name="PolynomWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>537</width>
<height>444</height>
</rect>
</property>
<property name="windowTitle">
<string>Полином</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="6">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="model">
<attribute name="title">
<string>Модель</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="3">
<widget class="QTableView" name="tableView">
<attribute name="horizontalHeaderMinimumSectionSize">
<number>40</number>
</attribute>
<attribute name="verticalHeaderMinimumSectionSize">
<number>40</number>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>40</number>
</attribute>
</widget>
</item>
<item row="2" column="3">
<layout class="QGridLayout" name="polynomResult">
<property name="topMargin">
<number>10</number>
</property>
<item row="0" column="1">
<widget class="QLabel" name="residualVarianceValueLabel">
<property name="text">
<string>undefined</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="scaledResidualVarianceValueLabel">
<property name="text">
<string>undefined</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="fStatisticLabel">
<property name="text">
<string>F1 - отношение Фишера</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="residualVarianceLabel">
<property name="text">
<string>Остаточная дисперсия:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="scaledResidualVarianceLabel">
<property name="text">
<string>Остаточная дисперсия (масштабированная):</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="rSquaredLabel">
<property name="text">
<string>Коэффициент множественной дереминизации</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="fStatisticValueLabel">
<property name="text">
<string>undefined</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="rSquaredValueLabel">
<property name="text">
<string>undefined</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="prediction">
<attribute name="title">
<string>Прогноз</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QTableView" name="predictionTableView">
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SquaredPolynomWindow</class>
<widget class="QDialog" name="SquaredPolynomWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>630</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string>Квадратичный полином</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTableView" name="tableView"/>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout_3">
<property name="topMargin">
<number>10</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="residualVarianceLabel">
<property name="text">
<string>Остаточная дисперсия:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="residualVarianceValueLabel">
<property name="text">
<string>undefined</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -71,6 +71,7 @@ class Ui_GenerateFactorWindow(object):
self.matSpinBox = QDoubleSpinBox(GenerateFactorWindow) self.matSpinBox = QDoubleSpinBox(GenerateFactorWindow)
self.matSpinBox.setObjectName(u"matSpinBox") self.matSpinBox.setObjectName(u"matSpinBox")
self.matSpinBox.setFont(font) self.matSpinBox.setFont(font)
self.matSpinBox.setDecimals(5)
self.matSpinBox.setMaximum(1000000.000000000000000) self.matSpinBox.setMaximum(1000000.000000000000000)
self.gridLayout.addWidget(self.matSpinBox, 1, 1, 1, 1) self.gridLayout.addWidget(self.matSpinBox, 1, 1, 1, 1)
@@ -78,6 +79,7 @@ class Ui_GenerateFactorWindow(object):
self.deviationSpinBox = QDoubleSpinBox(GenerateFactorWindow) self.deviationSpinBox = QDoubleSpinBox(GenerateFactorWindow)
self.deviationSpinBox.setObjectName(u"deviationSpinBox") self.deviationSpinBox.setObjectName(u"deviationSpinBox")
self.deviationSpinBox.setFont(font) self.deviationSpinBox.setFont(font)
self.deviationSpinBox.setDecimals(5)
self.deviationSpinBox.setMaximum(1000000.000000000000000) self.deviationSpinBox.setMaximum(1000000.000000000000000)
self.gridLayout.addWidget(self.deviationSpinBox, 2, 1, 1, 1) self.gridLayout.addWidget(self.deviationSpinBox, 2, 1, 1, 1)

View File

@@ -62,6 +62,7 @@ class Ui_GenerateWindow(object):
self.matSpinBox = QDoubleSpinBox(GenerateWindow) self.matSpinBox = QDoubleSpinBox(GenerateWindow)
self.matSpinBox.setObjectName(u"matSpinBox") self.matSpinBox.setObjectName(u"matSpinBox")
self.matSpinBox.setDecimals(5)
self.matSpinBox.setMaximum(1000000.000000000000000) self.matSpinBox.setMaximum(1000000.000000000000000)
self.gridLayout.addWidget(self.matSpinBox, 1, 1, 1, 1) self.gridLayout.addWidget(self.matSpinBox, 1, 1, 1, 1)
@@ -80,6 +81,7 @@ class Ui_GenerateWindow(object):
self.deviationSpinBox = QDoubleSpinBox(GenerateWindow) self.deviationSpinBox = QDoubleSpinBox(GenerateWindow)
self.deviationSpinBox.setObjectName(u"deviationSpinBox") self.deviationSpinBox.setObjectName(u"deviationSpinBox")
self.deviationSpinBox.setDecimals(5)
self.deviationSpinBox.setMaximum(1000000.000000000000000) self.deviationSpinBox.setMaximum(1000000.000000000000000)
self.gridLayout.addWidget(self.deviationSpinBox, 2, 1, 1, 1) self.gridLayout.addWidget(self.deviationSpinBox, 2, 1, 1, 1)

View File

@@ -1,82 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2023 Maxim Slipenko, Eugene Lazurenko.
#
# This file is part of Statapp
# (see https://github.com/shizand/statapp).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
## Form generated from reading UI file 'linear_polynom_window.ui'
##
## Created by: Qt User Interface Compiler version 5.15.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
class Ui_LinearPolynomWindow(object):
def setupUi(self, LinearPolynomWindow):
if not LinearPolynomWindow.objectName():
LinearPolynomWindow.setObjectName(u"LinearPolynomWindow")
LinearPolynomWindow.resize(630, 400)
self.gridLayout_2 = QGridLayout(LinearPolynomWindow)
self.gridLayout_2.setObjectName(u"gridLayout_2")
self.gridLayout = QGridLayout()
self.gridLayout.setObjectName(u"gridLayout")
self.tableView = QTableView(LinearPolynomWindow)
self.tableView.setObjectName(u"tableView")
self.tableView.horizontalHeader().setMinimumSectionSize(40)
self.tableView.verticalHeader().setMinimumSectionSize(40)
self.tableView.verticalHeader().setDefaultSectionSize(40)
self.gridLayout.addWidget(self.tableView, 0, 0, 1, 1)
self.gridLayout_3 = QGridLayout()
self.gridLayout_3.setObjectName(u"gridLayout_3")
self.gridLayout_3.setContentsMargins(-1, 10, -1, -1)
self.residualVarianceLabel = QLabel(LinearPolynomWindow)
self.residualVarianceLabel.setObjectName(u"residualVarianceLabel")
self.gridLayout_3.addWidget(self.residualVarianceLabel, 0, 0, 1, 1)
self.residualVarianceValueLabel = QLabel(LinearPolynomWindow)
self.residualVarianceValueLabel.setObjectName(u"residualVarianceValueLabel")
self.gridLayout_3.addWidget(self.residualVarianceValueLabel, 0, 1, 1, 1)
self.gridLayout.addLayout(self.gridLayout_3, 1, 0, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
self.retranslateUi(LinearPolynomWindow)
QMetaObject.connectSlotsByName(LinearPolynomWindow)
# setupUi
def retranslateUi(self, LinearPolynomWindow):
LinearPolynomWindow.setWindowTitle(QCoreApplication.translate("LinearPolynomWindow", u"\u041b\u0438\u043d\u0435\u0439\u043d\u044b\u0439 \u043f\u043e\u043b\u0438\u043d\u043e\u043c", None))
self.residualVarianceLabel.setText(QCoreApplication.translate("LinearPolynomWindow", u"\u041e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u0430\u044f \u0434\u0438\u0441\u043f\u0435\u0440\u0441\u0438\u044f:", None))
self.residualVarianceValueLabel.setText(QCoreApplication.translate("LinearPolynomWindow", u"undefined", None))
# retranslateUi

View File

@@ -58,6 +58,8 @@ class Ui_MainWindow(object):
self.linearPolynomAction.setObjectName(u"linearPolynomAction") self.linearPolynomAction.setObjectName(u"linearPolynomAction")
self.squaredPolynomAction = QAction(MainWindow) self.squaredPolynomAction = QAction(MainWindow)
self.squaredPolynomAction.setObjectName(u"squaredPolynomAction") self.squaredPolynomAction.setObjectName(u"squaredPolynomAction")
self.transformPolynomAction = QAction(MainWindow)
self.transformPolynomAction.setObjectName(u"transformPolynomAction")
self.centralwidget = QWidget(MainWindow) self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget") self.centralwidget.setObjectName(u"centralwidget")
self.gridLayout = QGridLayout(self.centralwidget) self.gridLayout = QGridLayout(self.centralwidget)
@@ -77,7 +79,7 @@ class Ui_MainWindow(object):
MainWindow.setCentralWidget(self.centralwidget) MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(MainWindow) self.menubar = QMenuBar(MainWindow)
self.menubar.setObjectName(u"menubar") self.menubar.setObjectName(u"menubar")
self.menubar.setGeometry(QRect(0, 0, 800, 27)) self.menubar.setGeometry(QRect(0, 0, 800, 21))
self.filemenu = QMenu(self.menubar) self.filemenu = QMenu(self.menubar)
self.filemenu.setObjectName(u"filemenu") self.filemenu.setObjectName(u"filemenu")
self.generatemenu = QMenu(self.menubar) self.generatemenu = QMenu(self.menubar)
@@ -107,6 +109,7 @@ class Ui_MainWindow(object):
self.analyzemenu.addAction(self.correlationAnalisisAction) self.analyzemenu.addAction(self.correlationAnalisisAction)
self.modelmenu.addAction(self.linearPolynomAction) self.modelmenu.addAction(self.linearPolynomAction)
self.modelmenu.addAction(self.squaredPolynomAction) self.modelmenu.addAction(self.squaredPolynomAction)
self.modelmenu.addAction(self.transformPolynomAction)
self.helpmenu.addAction(self.aboutmenuaction) self.helpmenu.addAction(self.aboutmenuaction)
self.retranslateUi(MainWindow) self.retranslateUi(MainWindow)
@@ -126,6 +129,7 @@ class Ui_MainWindow(object):
self.correlationAnalisisAction.setText(QCoreApplication.translate("MainWindow", u"\u041a\u043e\u0440\u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437", None)) self.correlationAnalisisAction.setText(QCoreApplication.translate("MainWindow", u"\u041a\u043e\u0440\u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437", None))
self.linearPolynomAction.setText(QCoreApplication.translate("MainWindow", u"\u041b\u0438\u043d\u0435\u0439\u043d\u044b\u0439 \u043f\u043e\u043b\u0438\u043d\u043e\u043c", None)) self.linearPolynomAction.setText(QCoreApplication.translate("MainWindow", u"\u041b\u0438\u043d\u0435\u0439\u043d\u044b\u0439 \u043f\u043e\u043b\u0438\u043d\u043e\u043c", None))
self.squaredPolynomAction.setText(QCoreApplication.translate("MainWindow", u"\u041a\u0432\u0430\u0434\u0440\u0430\u0442\u0438\u0447\u043d\u044b\u0439 \u043f\u043e\u043b\u0438\u043d\u043e\u043c", None)) self.squaredPolynomAction.setText(QCoreApplication.translate("MainWindow", u"\u041a\u0432\u0430\u0434\u0440\u0430\u0442\u0438\u0447\u043d\u044b\u0439 \u043f\u043e\u043b\u0438\u043d\u043e\u043c", None))
self.transformPolynomAction.setText(QCoreApplication.translate("MainWindow", u"\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f", None))
self.label.setText(QCoreApplication.translate("MainWindow", u"\u0421\u0422\u0410\u0422\u0418\u0421\u0422\u0418\u0427\u0415\u0421\u041a\u0418\u0415 \u0414\u0410\u041d\u041d\u042b\u0415", None)) self.label.setText(QCoreApplication.translate("MainWindow", u"\u0421\u0422\u0410\u0422\u0418\u0421\u0422\u0418\u0427\u0415\u0421\u041a\u0418\u0415 \u0414\u0410\u041d\u041d\u042b\u0415", None))
self.filemenu.setTitle(QCoreApplication.translate("MainWindow", u"\u0424\u0430\u0439\u043b", None)) self.filemenu.setTitle(QCoreApplication.translate("MainWindow", u"\u0424\u0430\u0439\u043b", None))
self.generatemenu.setTitle(QCoreApplication.translate("MainWindow", u"\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0435\u0439", None)) self.generatemenu.setTitle(QCoreApplication.translate("MainWindow", u"\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0435\u0439", None))

144
statapp/ui/ui_polynom_window.py generated Normal file
View File

@@ -0,0 +1,144 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2023 Maxim Slipenko, Eugene Lazurenko.
#
# This file is part of Statapp
# (see https://github.com/shizand/statapp).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
## Form generated from reading UI file 'polynom_window.ui'
##
## Created by: Qt User Interface Compiler version 5.15.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
class Ui_PolynomWindow(object):
def setupUi(self, PolynomWindow):
if not PolynomWindow.objectName():
PolynomWindow.setObjectName(u"PolynomWindow")
PolynomWindow.resize(537, 444)
self.gridLayout_2 = QGridLayout(PolynomWindow)
self.gridLayout_2.setObjectName(u"gridLayout_2")
self.tabWidget = QTabWidget(PolynomWindow)
self.tabWidget.setObjectName(u"tabWidget")
self.model = QWidget()
self.model.setObjectName(u"model")
self.gridLayout_3 = QGridLayout(self.model)
self.gridLayout_3.setObjectName(u"gridLayout_3")
self.gridLayout = QGridLayout()
self.gridLayout.setObjectName(u"gridLayout")
self.tableView = QTableView(self.model)
self.tableView.setObjectName(u"tableView")
self.tableView.horizontalHeader().setMinimumSectionSize(40)
self.tableView.verticalHeader().setMinimumSectionSize(40)
self.tableView.verticalHeader().setDefaultSectionSize(40)
self.gridLayout.addWidget(self.tableView, 1, 3, 1, 1)
self.polynomResult = QGridLayout()
self.polynomResult.setObjectName(u"polynomResult")
self.polynomResult.setContentsMargins(-1, 10, -1, -1)
self.residualVarianceValueLabel = QLabel(self.model)
self.residualVarianceValueLabel.setObjectName(u"residualVarianceValueLabel")
self.polynomResult.addWidget(self.residualVarianceValueLabel, 0, 1, 1, 1)
self.scaledResidualVarianceValueLabel = QLabel(self.model)
self.scaledResidualVarianceValueLabel.setObjectName(u"scaledResidualVarianceValueLabel")
self.polynomResult.addWidget(self.scaledResidualVarianceValueLabel, 1, 1, 1, 1)
self.fStatisticLabel = QLabel(self.model)
self.fStatisticLabel.setObjectName(u"fStatisticLabel")
self.polynomResult.addWidget(self.fStatisticLabel, 2, 0, 1, 1)
self.residualVarianceLabel = QLabel(self.model)
self.residualVarianceLabel.setObjectName(u"residualVarianceLabel")
self.polynomResult.addWidget(self.residualVarianceLabel, 0, 0, 1, 1)
self.scaledResidualVarianceLabel = QLabel(self.model)
self.scaledResidualVarianceLabel.setObjectName(u"scaledResidualVarianceLabel")
self.polynomResult.addWidget(self.scaledResidualVarianceLabel, 1, 0, 1, 1)
self.rSquaredLabel = QLabel(self.model)
self.rSquaredLabel.setObjectName(u"rSquaredLabel")
self.polynomResult.addWidget(self.rSquaredLabel, 3, 0, 1, 1)
self.fStatisticValueLabel = QLabel(self.model)
self.fStatisticValueLabel.setObjectName(u"fStatisticValueLabel")
self.polynomResult.addWidget(self.fStatisticValueLabel, 2, 1, 1, 1)
self.rSquaredValueLabel = QLabel(self.model)
self.rSquaredValueLabel.setObjectName(u"rSquaredValueLabel")
self.polynomResult.addWidget(self.rSquaredValueLabel, 3, 1, 1, 1)
self.gridLayout.addLayout(self.polynomResult, 2, 3, 1, 1)
self.gridLayout_3.addLayout(self.gridLayout, 0, 0, 1, 1)
self.tabWidget.addTab(self.model, "")
self.prediction = QWidget()
self.prediction.setObjectName(u"prediction")
self.gridLayout_4 = QGridLayout(self.prediction)
self.gridLayout_4.setObjectName(u"gridLayout_4")
self.predictionTableView = QTableView(self.prediction)
self.predictionTableView.setObjectName(u"predictionTableView")
self.predictionTableView.verticalHeader().setVisible(False)
self.gridLayout_4.addWidget(self.predictionTableView, 0, 0, 1, 1)
self.tabWidget.addTab(self.prediction, "")
self.gridLayout_2.addWidget(self.tabWidget, 0, 6, 1, 1)
self.retranslateUi(PolynomWindow)
self.tabWidget.setCurrentIndex(0)
QMetaObject.connectSlotsByName(PolynomWindow)
# setupUi
def retranslateUi(self, PolynomWindow):
PolynomWindow.setWindowTitle(QCoreApplication.translate("PolynomWindow", u"\u041f\u043e\u043b\u0438\u043d\u043e\u043c", None))
self.residualVarianceValueLabel.setText(QCoreApplication.translate("PolynomWindow", u"undefined", None))
self.scaledResidualVarianceValueLabel.setText(QCoreApplication.translate("PolynomWindow", u"undefined", None))
self.fStatisticLabel.setText(QCoreApplication.translate("PolynomWindow", u"F1 - \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0435 \u0424\u0438\u0448\u0435\u0440\u0430", None))
self.residualVarianceLabel.setText(QCoreApplication.translate("PolynomWindow", u"\u041e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u0430\u044f \u0434\u0438\u0441\u043f\u0435\u0440\u0441\u0438\u044f:", None))
self.scaledResidualVarianceLabel.setText(QCoreApplication.translate("PolynomWindow", u"\u041e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u0430\u044f \u0434\u0438\u0441\u043f\u0435\u0440\u0441\u0438\u044f (\u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f):", None))
self.rSquaredLabel.setText(QCoreApplication.translate("PolynomWindow", u"\u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0434\u0435\u0440\u0435\u043c\u0438\u043d\u0438\u0437\u0430\u0446\u0438\u0438", None))
self.fStatisticValueLabel.setText(QCoreApplication.translate("PolynomWindow", u"undefined", None))
self.rSquaredValueLabel.setText(QCoreApplication.translate("PolynomWindow", u"undefined", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.model), QCoreApplication.translate("PolynomWindow", u"\u041c\u043e\u0434\u0435\u043b\u044c", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.prediction), QCoreApplication.translate("PolynomWindow", u"\u041f\u0440\u043e\u0433\u043d\u043e\u0437", None))
# retranslateUi

View File

@@ -1,79 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2023 Maxim Slipenko, Eugene Lazurenko.
#
# This file is part of Statapp
# (see https://github.com/shizand/statapp).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
## Form generated from reading UI file 'squared_polynom_window.ui'
##
## Created by: Qt User Interface Compiler version 5.15.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
class Ui_SquaredPolynomWindow(object):
def setupUi(self, SquaredPolynomWindow):
if not SquaredPolynomWindow.objectName():
SquaredPolynomWindow.setObjectName(u"SquaredPolynomWindow")
SquaredPolynomWindow.resize(630, 400)
self.gridLayout_2 = QGridLayout(SquaredPolynomWindow)
self.gridLayout_2.setObjectName(u"gridLayout_2")
self.gridLayout = QGridLayout()
self.gridLayout.setObjectName(u"gridLayout")
self.tableView = QTableView(SquaredPolynomWindow)
self.tableView.setObjectName(u"tableView")
self.gridLayout.addWidget(self.tableView, 0, 0, 1, 1)
self.gridLayout_3 = QGridLayout()
self.gridLayout_3.setObjectName(u"gridLayout_3")
self.gridLayout_3.setContentsMargins(-1, 10, -1, -1)
self.residualVarianceLabel = QLabel(SquaredPolynomWindow)
self.residualVarianceLabel.setObjectName(u"residualVarianceLabel")
self.gridLayout_3.addWidget(self.residualVarianceLabel, 0, 0, 1, 1)
self.residualVarianceValueLabel = QLabel(SquaredPolynomWindow)
self.residualVarianceValueLabel.setObjectName(u"residualVarianceValueLabel")
self.gridLayout_3.addWidget(self.residualVarianceValueLabel, 0, 1, 1, 1)
self.gridLayout.addLayout(self.gridLayout_3, 1, 0, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
self.retranslateUi(SquaredPolynomWindow)
QMetaObject.connectSlotsByName(SquaredPolynomWindow)
# setupUi
def retranslateUi(self, SquaredPolynomWindow):
SquaredPolynomWindow.setWindowTitle(QCoreApplication.translate("SquaredPolynomWindow", u"\u041a\u0432\u0430\u0434\u0440\u0430\u0442\u0438\u0447\u043d\u044b\u0439 \u043f\u043e\u043b\u0438\u043d\u043e\u043c", None))
self.residualVarianceLabel.setText(QCoreApplication.translate("SquaredPolynomWindow", u"\u041e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u0430\u044f \u0434\u0438\u0441\u043f\u0435\u0440\u0441\u0438\u044f:", None))
self.residualVarianceValueLabel.setText(QCoreApplication.translate("SquaredPolynomWindow", u"undefined", None))
# retranslateUi

View File

@@ -22,7 +22,9 @@ import sys
from PySide2.QtCore import QSize from PySide2.QtCore import QSize
from PySide2.QtGui import QIcon from PySide2.QtGui import QIcon
from PySide2.QtWidgets import QMessageBox from PySide2.QtWidgets import QMessageBox, QDoubleSpinBox, QStyledItemDelegate
from statapp.constants import NUMBERS_PRECISION
def resourcePath(relative): def resourcePath(relative):
@@ -58,3 +60,19 @@ def buildMessageBox(title, text, icon, buttons, defaultButton):
msgBox.setDefaultButton(defaultButton) msgBox.setDefaultButton(defaultButton)
return msgBox return msgBox
class FloatDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
QStyledItemDelegate.__init__(self, parent=parent)
def createEditor(self, parent, option, index):
editor = QDoubleSpinBox(parent)
editor.setDecimals(NUMBERS_PRECISION)
editor.setMaximum(10**8)
editor.setMinimum(-10**8)
return editor
def displayText(self, value, locale):
# Грязный хак, скорее всего нужно было использовать locale
return f'{value:.{NUMBERS_PRECISION}f}'

View File

@@ -20,10 +20,11 @@
from PySide2.QtWidgets import QDialog, QHeaderView from PySide2.QtWidgets import QDialog, QHeaderView
from statapp.calculations import varianceAnalysis from statapp.calculations import varianceAnalysis
from statapp.constants import NUMBERS_PRECISION
from statapp.mathtex_header_view import MathTexHeaderView from statapp.mathtex_header_view import MathTexHeaderView
from statapp.models.variance_analysis_model import VarianceAnalysisModel from statapp.models.variance_analysis_model import VarianceAnalysisModel
from statapp.ui.ui_variance_analysis_window import Ui_VarianceAnalysisWindow from statapp.ui.ui_variance_analysis_window import Ui_VarianceAnalysisWindow
from statapp.utils import addIcon from statapp.utils import addIcon, FloatDelegate
class VarianceAnalysisWindow(QDialog): class VarianceAnalysisWindow(QDialog):
@@ -33,7 +34,8 @@ class VarianceAnalysisWindow(QDialog):
self.ui.setupUi(self) self.ui.setupUi(self)
res = varianceAnalysis(data) res = varianceAnalysis(data)
self.model = VarianceAnalysisModel(res.round(2)) self.model = VarianceAnalysisModel(res.round(NUMBERS_PRECISION))
self.ui.tableView.setItemDelegate(FloatDelegate())
self.ui.tableView.setModel(self.model) self.ui.tableView.setModel(self.model)
self.ui.tableView.setVerticalHeader( self.ui.tableView.setVerticalHeader(
MathTexHeaderView(self.ui.tableView) MathTexHeaderView(self.ui.tableView)