逻辑回归真假新闻分类:Python 图形用户界面
逻辑回归真假新闻分类:Python 图形用户界面
本程序使用 Python 和 PySide6 构建了一个逻辑回归真假新闻分类的图形用户界面,允许用户加载数据、预处理数据、可视化数据、训练模型、预测和评估结果。
导入所需模块
import pathlib # 路径操作模块
import time # 时间模块
import traceback # 异常跟踪模块
from typing import Optional, Callable, Generator, Union # 类型提示模块
import pandas as pd # pandas数据处理模块
from PySide6.QtCore import QAbstractTableModel, Qt, QRunnable, Signal, QThreadPool, QThread, QTimer # PySide6模块
from PySide6.QtGui import QPixmap, QIcon # PySide6图形用户界面模块
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QLabel, QFileDialog, QTableView, QStackedWidget, \
QVBoxLayout, QScrollArea, QWidget, QHeaderView, QMessageBox, QDialog # PySide6图形用户界面模块
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas # Matplotlib绘图模块
from matplotlib.figure import Figure # Matplotlib绘图模块
from ui_windows import Ui_MainWindow # 导入UI文件
import main # 导入主程序
# 定义数据表模型,将表中数据显示
class TableModel(QAbstractTableModel):
def __init__(self, data: pd.DataFrame):
super().__init__()
self._data = data
def rowCount(self, parent=None):
return self._data.shape[0]
def columnCount(self, parent=None):
return self._data.shape[1]
def data(self, index, role=None):
if role == Qt.DisplayRole:
return str(self._data.iloc[index.row(), index.column()])
return None
def headerData(self, section, orientation, role=None):
if role == Qt.DisplayRole:
if orientation == Qt.Horizontal:
return str(self._data.columns[section])
else:
return str(self._data.index[section])
return None
def sort(self, column, order=None):
self.layoutAboutToBeChanged.emit()
self._data.sort_values(self._data.columns[column], ascending=order == Qt.AscendingOrder, inplace=True)
self.layoutChanged.emit()
@property
def df(self):
return self._data
# 定义数据表格控件
class TableWidget(QTableView):
def __init__(self, data: Optional[pd.DataFrame] = None):
super().__init__()
if data is not None:
self.setModel(TableModel(data))
# 定义任务,返回指令
class Task:
def __init__(
self,
func: Callable[..., Generator[Union[str, pd.DataFrame], None, None]],
*args,
**kwargs
):
self._func = func
self._args = args
self._kwargs = kwargs
def __call__(self):
try:
yield from self._func(*self._args, **self._kwargs)
except Exception as e:
traceback.print_exc()
yield str(e)
# 定义工作线程,工作状态汇报
class Worker(QThread):
resulted = Signal(pd.DataFrame)
step = Signal(str)
image = Signal(pathlib.Path)
wrapper = Signal(list)
stop = Signal()
def __init__(self, parent=None):
super().__init__(parent)
self._task = None
def bind_task(self, func, *args, **kwargs):
self._task = Task(func, *args, **kwargs)
def run(self):
if self._task is None:
raise ValueError('Task not bind')
print('开始执行')
for value in self._task():
if isinstance(value, pd.DataFrame):
self.resulted.emit(value)
elif isinstance(value, str):
print('收到', value)
self.step.emit(value)
time.sleep(0.1)
elif isinstance(value, pathlib.Path):
print('图片', value)
self.image.emit(value)
elif isinstance(value, list):
self.wrapper.emit(value)
self.stop.emit()
# 定义Matplotlib可视化图控件
class MatplotlibWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.figure = Figure()
self.canvas = FigureCanvas(self.figure)
layout = QVBoxLayout(self)
layout.addWidget(self.canvas)
self.setLayout(layout)
def draw(self, data: pd.DataFrame):
pass
# 定义后台Matplotlib绘图工作线程
class DrawWorker(QRunnable):
def __init__(self, func, *args, **kwargs):
super().__init__()
self._func = func
self._args = args
self._kwargs = kwargs
def run(self):
self._func(*self._args, **self._kwargs)
# 定义图片控件,实现图片显示
class ImageWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.label = QLabel()
self.label.setAlignment(Qt.AlignCenter)
layout = QVBoxLayout(self)
layout.addWidget(self.label)
self.setLayout(layout)
self.setObjectName('#image')
self.setStyleSheet(
'''
#image {
background-color: white;
border: 1px solid black;
border-radius: 5px;
}
'''
)
def draw(self, path: pathlib.Path):
max_width = 1200
pix = QPixmap(str(path))
if pix.width() > max_width:
pix = pix.scaledToWidth(max_width, Qt.SmoothTransformation)
self.label.setPixmap(
pix
)
self.setFixedSize(
pix.width() + 2, pix.height() + 2
)
# 定义提示对话框
class TipsDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle('Tips')
self.resize(300, 200)
self.setLayout(QVBoxLayout())
self.label = QLabel('正在处理数据,请稍后……')
self.layout().addWidget(self.label)
def update_text(self, text):
self.label.setText(text)
# 定义主窗口
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.setWindowTitle('逻辑回归真假新闻分类')
self.setWindowIcon(
QIcon(str(pathlib.Path(__file__).parents[1] / 'ui/icon.png'))
)
self.stack = QStackedWidget()
self.widget.setLayout(QVBoxLayout())
self.widget.layout().addWidget(self.stack)
self.thread_pool = QThreadPool(self)
self.table = TableWidget()
self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.stack.addWidget(self.table)
self.area = QScrollArea()
self.area.setWidgetResizable(True)
self.container = QWidget()
self.area.setWidget(self.container)
self.container.setLayout(QVBoxLayout())
self.stack.addWidget(self.area)
self.checkBox.setChecked(True)
self.checkBox_2.setChecked(True)
self.checkBox_3.setChecked(True)
self.checkBox.setEnabled(False)
self.checkBox_2.setEnabled(False)
self.checkBox_3.setEnabled(False)
self.worker = Worker()
self.worker.resulted.connect(self.update_table)
self.worker.step.connect(self.update_step)
self.worker.stop.connect(self.end)
self.worker.image.connect(self.update_image)
self.worker.wrapper.connect(self.update_wrapper)
self.widget_2.setFixedWidth(300)
self.btn_load.clicked.connect(self.load_file)
self._model: Optional[TableModel] = None
self.btn_data_pre.clicked.connect(self.process_data)
self.btn_chart.clicked.connect(self.draw)
self.btn_chart.setEnabled(False)
self.horizontalSlider.valueChanged.connect(self.update_slider)
self.horizontalSlider.setValue(80)
self.btn_train.clicked.connect(self.train)
self.btn_train.setEnabled(False)
self.btn_pre.clicked.connect(self.predict)
self.btn_pre.setEnabled(False)
self.pushButton.clicked.connect(self.evaluate)
self.pushButton.setEnabled(False)
# 加载文件
def load_file(self):
filename, _ = QFileDialog.getOpenFileName(self, 'Open file', '', 'CSV files (*.csv)')
if filename:
self._reset_status(True)
self.statusBar().showMessage(filename)
data = main.load_data(filename)
self._model = TableModel(data)
self.table.setModel(self._model)
# 重置状态
def _reset_status(self, status: bool = True):
self.btn_data_pre.setEnabled(status)
def update_step(self, step: str):
self.statusBar().showMessage(step)
def update_table(self, data: pd.DataFrame):
self._model = TableModel(data)
self.table.setModel(self._model)
def update_wrapper(self, wrapper):
print(wrapper)
text = '\n'.join(wrapper)
tip = TipsDialog(self)
tip.setWindowTitle('评估结果')
tip.update_text(text)
tip.exec()
def update_slider(self, value):
# 显示划分比例
text = round(value / 100, 1)
self.label_split.setText(
f'训练集比例:{text}\n测试集比例:{round(1 - text, 1)}'
)
def process_data(self):
if not self._model:
self.tips('请先加载数据')
return
try:
self.btn_data_pre.setEnabled(False)
self.worker.bind_task(main.data_process)
self.worker.start()
except Exception as e:
traceback.print_exc()
def end(self):
# self.statusBar().showMessage('处理完成')
self.btn_chart.setEnabled(True)
self.btn_train.setEnabled(True)
self.tips('运行完成')
def tips(self, message):
QMessageBox.information(self, '提示', message) # 弹出提示框,标题为“提示”,内容为message
def update_image(self, image):
self.stack.setCurrentIndex(1)
img = ImageWidget(self)
img.draw(image)
self.container.layout().addWidget(img)
# 滚动到底部
QTimer.singleShot(5, self.scroll_bottom)
def scroll_bottom(self):
self.area.verticalScrollBar().setValue(
self.area.verticalScrollBar().maximum()
)
def draw(self):
if not self._model:
self.tips('请先加载数据')
return
self.statusBar().showMessage('正在绘制,请稍后……')
self.worker.bind_task(main.data_visualization)
self.worker.start()
def train(self):
if not self._model:
self.tips('请先加载数据')
return
self.statusBar().showMessage('正在训练,请稍后……')
self.worker.bind_task(main.train, round(1 - self.horizontalSlider.value() / 100, 1))
self.worker.start()
self.btn_pre.setEnabled(True)
def predict(self):
self.statusBar().showMessage('正在训练,请稍后……')
self.worker.bind_task(main.predict)
self.worker.start()
self.pushButton.setEnabled(True)
def evaluate(self):
self.statusBar().showMessage('正在训练,请稍后……')
self.worker.bind_task(main.evaluate)
self.worker.start()
if __name__ == '__main__':
app = QApplication([])
window = MainWindow()
window.show()
app.exec()
程序说明
这是一个Python程序,用于构建一个逻辑回归真假新闻分类的图形用户界面。程序分为几个部分:
-
导入所需模块:程序中使用了许多Python模块,包括路径操作模块、时间模块、异常跟踪模块、类型提示模块、pandas数据处理模块、PySide6图形用户界面模块、Matplotlib绘图模块等。
-
定义数据表模型:由于程序需要显示数据表格,因此定义了一个TableModel类,该类继承自QAbstractTableModel,用于将表中数据显示出来。
-
定义数据表格控件:定义了一个TableWidget类,该类继承自QTableView,用于显示数据表格控件。
-
定义任务:定义了一个Task类,用于返回指令。
-
定义工作线程:定义了一个Worker类,继承自QThread,用于执行工作,并在执行过程中汇报工作状态。
-
定义Matplotlib可视化图控件:定义了一个MatplotlibWidget类,用于显示Matplotlib可视化图控件。
-
定义后台Matplotlib绘图工作线程:定义了一个DrawWorker类,用于在后台执行Matplotlib绘图工作。
-
定义图片控件:定义了一个ImageWidget类,用于显示图片控件。
-
定义提示对话框:定义了一个TipsDialog类,用于弹出提示对话框。
-
定义主窗口:定义了一个MainWindow类,用于构建整个图形用户界面。
-
程序入口:在程序入口处,实例化了一个QApplication对象,然后创建MainWindow对象并显示出来,最后通过app.exec()启动程序。
原文地址: https://www.cveoy.top/t/topic/oDI1 著作权归作者所有。请勿转载和采集!