欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

Python实现矩阵基尼系数计算器

最编程 2024-01-19 11:26:40
...


为什么要实现矩阵计算器?
答:因为可以带来便利,相当于把matlib中对矩阵的基本操作抽离出来,降低操作门槛,同时也更加灵活*,代码可以自己控制,功能可以自己添加修改。
–参考了pyqt5的example中的calculator。有关矩阵的库主要使用了sympy,参考了大佬的博客:sympy矩阵操作

计算器样子,丑媳妇早晚要见大大们, 后续我学好了qss和style 再优化它~/滑稽/逃:

python 计算矩阵的基尼系数 python矩阵计算器_算法


言归正传,输入,输出格式举例(转置):

python 计算矩阵的基尼系数 python矩阵计算器_pyqt_02

一些想法:

1.实现计算器之前可以先在https://www.draw.io/上绘制模型,这样布局的时候会更有底气,如:

python 计算矩阵的基尼系数 python矩阵计算器_算法_03


2.如果想要把他变成exe,先

pip install pyinstaller

然后:

pyinstaller -F -w -p /d/software/python3.7.4/lib calc.py

-F是生产单个文件,-w是图像界面显示(注意:需要在windows下),-p指出python lib的位置
之后运行会报错,没事不慌,
打开生产的 calc.spec,在第二、三行插入

import sys
sys.setrecursionlimit(5000)

最后:

pyinstaller calc.spec

就在dist文件夹下生产了calc.exe

矩阵计算器代码:

#!/usr/bin/python3
# -*- encoding_utf-8 -*-
import sys
sys.setrecursionlimit(5000) #为了用pyinstaller生产exe添加
if hasattr(sys, 'frozen'):	#为了生产exe添加
    os.environ['PATH'] = sys._MEIPASS + ";" + os.environ['PATH']
from PyQt5.QtWidgets import (QToolButton, QFrame, QVBoxLayout, QHBoxLayout, QGridLayout,
                             QApplication, QTextEdit, QSizePolicy, QLineEdit)
from PyQt5.QtGui import QIntValidator, QTextOption, QTextCursor
from sympy import symbols, Matrix, solve, diff, eye

class Button(QToolButton):
    def __init__(self, text, parent=None):
        super(Button, self).__init__(parent)

        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        self.setText(text)

    def sizeHint(self):
        size = super(Button, self).sizeHint()
        size.setHeight(size.height() + 50)
        size.setWidth(max(size.width(), size.height()))
        return size     
        
class Calc(QFrame):
    NumDigitButtons = 10
    def __init__(self):
        super().__init__()
        self.initData()
        self.initUI()
        self.initConnect()

    def initData(self):
        pass

    def initUI(self):
        self.layout = QVBoxLayout()
        self.createDisplayBox()
        self.createInputBox()

        self.setLayout(self.layout)
        self.show()

    def initConnect(self):
        self.input.textChanged.connect(self.cursorChange)

    def cursorChange(self):
        print('cursorChange')
        cursor =  self.input.textCursor()
        cursor.movePosition(QTextCursor.End)
        self.input.setTextCursor(cursor)

    def createDisplayBox(self):
        layout = QHBoxLayout()
        self.input = QTextEdit()
        self.output = QTextEdit()
        self.output.setReadOnly(True) 
        self.output.setWordWrapMode(QTextOption.NoWrap)

        layout.addWidget(self.input)
        layout.addWidget(self.output)
        layout.setStretch(1.5, 1)
        self.layout.addLayout(layout)

    def createInputBox(self):
        layout = QGridLayout()
        self.digitButtons = []
        for i in range(Calc.NumDigitButtons):
            self.digitButtons.append(self.createButton(str(i),
                    self.digitClicked))

        self.reverseButton = self.createButton("求逆",
                self.reverseOperateClicked)
        self.powButton =  self.createButton("次方:",
                self.powOperatorClicked)
        self.powLineEdit = QLineEdit()
        self.powLineEdit.setValidator(QIntValidator())
        self.transposeButton =  self.createButton("转置",
                self.transposeOperatorClicked)
        self.eigenvectButton = self.createButton("特征向量",
                self.eigenvectOperatorClicked)
        self.eigenvalButton = self.createButton("特征值",
                self.eigenvalOperatorClicked)
        self.rankButton = self.createButton("秩",
                self.rankOperatorClicked)
        self.detButton = self.createButton("行列式",
                self.detOperatorClicked)
        self.rrefButton = self.createButton("最简型",
                self.rrefOperatorClicked)
        self.blankSpaceButton = self.createButton(" ",
                self.balnkOperatorClicked)
        self.EnterButton = self.createButton("Enter",
                self.EnterOperatorClicked)
        self.clearButton = self.createButton("Clear",
                self.clearOperatorClicked)
        self.minusButton = self.createButton("-",
                self.minuxOperatorClicked)


        for i in range(1, Calc.NumDigitButtons):
            row = ((9 - i) / 3) + 2
            column = ((i - 1) % 3) + 1
            layout.addWidget(self.digitButtons[i], row, column)
        layout.addWidget(self.digitButtons[0], 5, 1)
        layout.addWidget(self.reverseButton, 2, 4)
        layout.addWidget(self.powButton, 1, 1)
        layout.addWidget(self.powLineEdit,1, 2, 1, 2)
        layout.addWidget(self.transposeButton, 1, 4)
        layout.addWidget(self.eigenvectButton, 3, 5)
        layout.addWidget(self.eigenvalButton, 4, 5)
        layout.addWidget(self.rankButton, 3, 4)
        layout.addWidget(self.detButton, 1, 5)
        layout.addWidget(self.rrefButton, 2, 5)
        layout.addWidget(self.blankSpaceButton, 5, 2, 1, 2)
        layout.addWidget(self.EnterButton, 4, 4)
        layout.addWidget(self.clearButton, 5, 5)
        layout.addWidget(self.minusButton, 5, 4)
        self.layout.addLayout(layout)

    def formateInput(self, inputText):
        inputText.strip()
        print("inputText", inputText, type(inputText))
        inputText += ' \n'
        listForMat = list()
        templist = list()
        currentNum = ''
        for char in inputText:
            print(char)
            if char.isalnum():
                currentNum += char

            if char == '-':
                currentNum += char 

            if char.isspace():
                if currentNum.isalnum() or currentNum[1:].isalnum():
                    templist.append(int(currentNum))
                currentNum = ''

            if char == '\n' and len(templist) != 0:
                listForMat.append(templist)
                templist = []

        return listForMat

    def formatOutput(self, matrix):
        output = ''
        row, column = matrix.shape
        print(column)
        count = 0
        for i in matrix:

            print(count)
            if count % column == 0 and count != 0:
                output += '\n' 
            output += str(i) + '  '
            count += 1
        return output

    def reverseOperateClicked(self):
        text = self.input.toPlainText()
        print('text :', text)
        listForMat = self.formateInput(text)
        print(listForMat)
        A = Matrix(listForMat)
        # 不是方阵或者不满秩 无法求逆
        if A.shape[0] != A.shape[1] or A.rank() != A.shape[0]:
            self.abortOperation()
            return
        reverse_A = A ** -1
        output = self.formatOutput(reverse_A)

        self.output.setPlainText(output)

    def abortOperation(self):
        self.output.setPlainText("####")

    def powOperatorClicked(self):
        n = self.powLineEdit.text()
        if n.isalnum():
            text = self.input.toPlainText()
            listForMat = self.formateInput(text)
            A = Matrix(listForMat)

            # 不是方阵没法求次方
            if A.shape[0] != A.shape[1]:
                self.abortOperation()
                return
            output = ''
            output_forhuman = ''
            eigenvalmap =  A.eigenvals()
            iseigenvals_int = True

            for key in eigenvalmap.keys():
                if key % 1 != 0:
                    print('isinstance(key, int):', key)
                    iseigenvals_int = False
                    break

            if iseigenvals_int and A.rank() > 1:
                try:
                    answer = pow_Matrix(A, int(n))
                    A = answer[0]
                    output_forhuman = str(answer[1])
                    output = output_forhuman + '\n \n' 

                except Exception:
                    A = A ** int(n)
            else: 
                A = A ** int(n)          
            output += self.formatOutput(A)
            self.output.setPlainText(output)

    def transposeOperatorClicked(self):
        text = self.input.toPlainText()
        print('text :', text)
        listForMat = self.formateInput(text)
        print(listForMat)
        A = Matrix(listForMat)
        print(A)
        A = Matrix(A)
        transpose_A = A.T
        output = self.formatOutput(transpose_A)

        self.output.setPlainText(output)

    def eigenvectOperatorClicked(self):
        text = self.input.toPlainText()
        listForMat = self.formateInput(text)
        A = Matrix(listForMat)
        # 不是方正没法求特征向量
        if A.shape[0] != A.shape[1]:
            self.abortOperation()
            return
        eigenvectList = A.eigenvects()
        output = ''
        for i in range(len(eigenvectList)):
            output += '特征值:' + str(eigenvectList[i][0])
            output += ' ,数量:' + str(eigenvectList[i][1])
            output += ' ,特征向量: \n'
            for j in range(len(eigenvectList[i][2])):# 可能有多个特征向量
                output += self.formatOutput(eigenvectList[i][2][j]) + ' '
                output += '\n \n'
            output += '\n'

        self.output.setPlainText(output)

    def eigenvalOperatorClicked(self):
        text = self.input.toPlainText()
        listForMat = self.formateInput(text)
        A = Matrix(listForMat)
        # 不是方正没法求特征值
        if A.shape[0] != A.shape[1]:
            self.abortOperation()
            return
        eigenvalmap = A.eigenvals()
        output = ''
        for val, num in eigenvalmap.items():
            for i in range(num):
                output += str(val) + ' '
        self.output.setPlainText(output)

    def rankOperatorClicked(self):
        text = self.input.toPlainText()
        listForMat = self.formateInput(text)
        A = Matrix(listForMat)

        rank = A.rank()
        output = str(rank)
        self.output.setPlainText(output)

    def detOperatorClicked(self):
        text = self.input.toPlainText()
        listForMat = self.formateInput(text)
        A = Matrix(listForMat)
        # 不是方正没法求行列式
        if A.shape[0] != A.shape[1]:
            self.abortOperation()
            return
        det = A.det()
        output = str(det)
        self.output.setPlainText(output)

    def rrefOperatorClicked(self):
        text = self.input.toPlainText()
        listForMat = self.formateInput(text)
        A = Matrix(listForMat)

        rrf_matrix = A.rref()[0]
        output = self.formatOutput(rrf_matrix)
        self.output.setPlainText(output)

    def balnkOperatorClicked(self):
        text = self.input.toPlainText()
        text += ' '
        self.input.setPlainText(text)

    def EnterOperatorClicked(self):
        text = self.input.toPlainText()
        text += '\n'
        self.input.setPlainText(text)

    def minuxOperatorClicked(self):
        text = self.input.toPlainText()
        text += '-'
        self.input.setPlainText(text)

    def clearOperatorClicked(self):
        self.output.setPlainText('')
        self.input.setPlainText('')
        self.powLineEdit.setText('')

    def createButton(self, text, member):
        button = Button(text)
        button.clicked.connect(member)
        return button

    def digitClicked(self):
        clickedButton = self.sender()
        digitValue = int(clickedButton.text())
        self.input.setPlainText(self.input.toPlainText() + str(digitValue))


def getYuExpression(n):
    # 确定特征值后获取余数的表达式
     # 次数比特征值次数少1,而range默认如取到倒数第二个
    symbolsList = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']
    expression = symbols(symbolsList[0])
    for i in range(1, n):
        expression += symbols(symbolsList[i]) * symbols("x") ** (i)
    print('expression:', expression)
    return expression

def findSame(numlist):
    '''
    输入特征值图
    输出最多的重复次数的数字,和最多重复次数
    '''
    maxSame = 0 
    for tzz, same_num in numlist.items():
        if maxSame < same_num:
            maxSame = same_num
            maxSameNum = tzz
    return maxSameNum, maxSame

def calEquation(A, expression, tzz, same_num, same_nums):
    expressionList = list()
    for key in tzz.keys():
        expressionList.append(expression.subs('x', key))

    for i in range(same_nums - 1):
        dify = diff(expression, symbols('x'))
        expression = dify
        print('dify :', dify)
        expressionList.append(dify.subs('x', same_num))
    print('expressionList: ', expressionList)

    # 用sympy.solve 求解方程组
    answers = solve(expressionList)
    print('answers', answers)

    answerList = list()
    human_answerList = list()

    # 用列表格式化a,b,c..

    for key, value in answers.items():
        if key == symbols('a'):
            human_answerList.append((key, value))
            size = A.rank()
            value = value * eye(size)
            answerList.append((key, value))
        else:
            answerList.append((key, value))
            human_answerList.append((key, value))

    # 列表中添加变量x的值为A
    answerList.append((symbols('x'), A))
    return (answerList, human_answerList)

def pow_Matrix(A, n): # 老师人赛电脑方法的代码实现 
    tzz = A.eigenvals()  # "返回值为一个字典,特征值:根的重数"
    rank = A.rank()  # 获得矩阵A的秩
    yu_expression = getYuExpression(rank)  # 获得余数的表达式

    same_num, same_nums = findSame(tzz)
    print('same_num:', same_num, '  same_nums:', same_nums)

    expression = symbols("x") ** n - yu_expression
    print(expression)
    # 例如 记录了变量 a,b 的值
    result = calEquation(A, expression, tzz, same_num, same_nums)
    answerList = result[0]
    human_answeList = result[1]
    print('answerList :', answerList)
    answer = yu_expression.subs(answerList)
    print('answer: ', answer)
    human_answer = yu_expression.subs(human_answeList)
    return (answer, human_answer)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    calc = Calc()
    sys.exit(app.exec_())

说下代码中pow_Matrix想法的来源:

如何求矩阵A的100次方?矩阵论老师让我们手算,纳尼(⊙o⊙)?,老师:呵呵一笑我这里有更高级的方法,人脑赛电脑哦!

题目如下:

python 计算矩阵的基尼系数 python矩阵计算器_矩阵计算器_04

解法:

python 计算矩阵的基尼系数 python矩阵计算器_python 计算矩阵的基尼系数_05


代码中的pow_Matrix函数的实现完全就是仿照这一步步下来的。(当特征值是整数的时候,才执行了pow_Matrix,因为特征值奇形怪状的话这种方法会比较飙不动。)

用计算器进行计算:(比正常的A**1000计算多了的第一行和上图答案最后一行的解答是对应的)

python 计算矩阵的基尼系数 python矩阵计算器_算法_06