一,前言:
在我上一篇blog QChart任务数预测项目实战--Apple的学习笔记 中有一个python预测任务,今天完成了并且进行QT c++及python混合编程后的集成。
二,功能:
要进行预测每天会新学习多少项内容。然后继续按艾宾浩斯曲线来处理。
三,思路分析:
哪些先分析下数据有什么特征,就会发现每天学习数量几乎都少于10项。然后周末或周一新学习的数量会笔记多。周五新学习的数量会比较少。这是我的个人规律,周末不上班,所以学习数量可以多些,周五一般就想休息了。
四,数学建模:
这个不属于线性回归,属于数据分类问题。那么预测每天会新学习多少项内容的数学模型就简化为如下:
预测周一的学习数量,周二的学习数量一直到周日的学习数量,而且数组范围为【1,10】。
机器学习里面首先想到朴素贝叶斯,由于此模型都没有什么条件概率。所以又简化为了计算周一出现[0,10]中哪个概率最大,则预测出将来的周一新学习项的数量。同理去推导周二到周日新学习的数量。
python算法模拟实验
mylist1=[[5,1,4,1,0,5], #周一
[1,2,1,3,3,4]] #周二
useValue=[0,0]
def forecast():
for date in range(2):
maxNum = 0
for i in range(10,-1,-1): # 10 to 0 开始遍历
if (mylist1[date].count(i))>maxNum: #select the first max value,if counter is the same,select the max one
maxNum = mylist1[date].count(i)
useValue[date] =i
print (useValue)
if __name__ == '__main__':
forecast()
输出结果
[5, 3]
代表周一预测新学习数量加5,周二加3。
五,总结
由于我是2019-10-01开始使用这套系统的,所以当前的训练数据就比较少,不准确。我的概率在某个星期n计算会发现都是一样的,在这样的情况下使用的是最大值就不太准。
六,遇到的问题记录
1.解决了python37_d无法打开的问题,自己再copy一个然后重命名为_d.lib即可。
2.Py_IsInitialized报错,需要按网上说的修改python的include中的一个头文件。
3.添加python模块lib的方法可以右击工程添加,也可以手工添加,最后用的是手工在pro文件中添加。
七,学到的技术总结
- QT c++和python的混合编程技能。
- 复习了机器学习中的朴素贝叶斯。
- QT Vector的copy用<<即可。
- 掌握了datetime的各种转换。
- 学习了python collections进行归类的字典输出。
八,github源码上传
https://github.com/AppleCai/taskForecast
九,运行效果图
十,python源码
import sqlite3
from datetime import datetime
from collections import Counter
mydatelist=[
[], #周日
[], #周一
[], #周二
[], #周三
[], #周四
[], #周五
[], #周六
]
useValue=[0,0,0,0,0,0,0] # 周日,周一~周六每天新学的任务数
def connectUserDb():
con = sqlite3.connect(r'D:\Djangoproj\myWebTest\db.sqlite3')
return con
def queryUserRecords(con):
mytemplist = []
# 因为我的django工程师10月初做的,所以从2019年10月1日后的数据算是有效的。然后开始统计
cursor = con.execute("SELECT modify_date FROM myfile_basicinfo WHERE modify_date>='2019-10-01'")
# 仅提取日期字符串,不需要时间
for item in cursor:
mytemplist.append(item[0][0:10])
# 对每一相同日期归类,以字典显示{日期:出现次数}
res = Counter(mytemplist)
print(res)
for key in res:
# 先将str转成datatime格式后再转为周几
anyday = datetime.strptime(key, '%Y-%m-%d').strftime("%w") # key为日期字符串,做处理
tempnum = res[key]
# 预测的每天新增学习数量(即出现次数)不超过10项,超过10则用10代表
if (tempnum>10):
tempnum = 10
mydatelist[int(anyday)].append(tempnum) # 将日期转为周几,并将出现次数copy到数组。
def forecast():
for date in range(7): # date 0 to 6
maxNum = 0
for i in range(10,-1,-1): # i is from 10 to 0
if (mydatelist[date].count(i))>maxNum: # 若出现次数相同,则选择字数最大的值作为预测性学习数量
maxNum = mydatelist[date].count(i)
useValue[date] =i
print (useValue)
def maintask():
connect=connectUserDb() # 连接数据库
queryUserRecords(connect) # 查询曾经学习的记录,并且处理数据获得每天(周一~周日)新学习的数量
forecast() # 进行机器分类学习,在0-10之前出现最大的概率
return useValue
if __name__ == '__main__':
maintask()
十一,QT widget部分源码
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
pythonCode();
ui->setupUi(this);
//QDateTime curDateTime=QDateTime::currentDateTime();
curDate=QDate::currentDate();
lastDate = curDate.addDays(15);
ui->txtDate->setText(curDate.toString("yyyy-MM-dd"));
ui->cb_rangeselect->addItem("one week");
ui->cb_rangeselect->addItem("two week");
connectSQL();
addmyForecast();
}
void Widget::pythonCode()
{
Py_Initialize();
//如果初始化失败,返回
if(!Py_IsInitialized())
{
qDebug()<<"Initlize error";
}
else
{
qDebug() << "inititalize success";
}
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')"); //即exe运行目录下放入python文件
PyObject* pModule =PyImport_ImportModule("forecast");
if(!pModule)
{
qDebug()<<"can not open python file";
}
else
{
qDebug() << "Import success";
}
// 加载函数maintask()
PyObject *pLoadFunc = PyObject_GetAttrString(pModule, "maintask");
if (!pLoadFunc) {
printf("get func failed!");
}
else {
qDebug() << "get func success";
}
PyObject *retObjectX = PyObject_CallObject(pLoadFunc, nullptr); // 获得python脚本返回数据
if (retObjectX == nullptr) {
qDebug() << "no return value";
return ;
}
int row = PyList_Size(retObjectX);
for (int i = 0; i < row; ++i) {
PyObject *singleItem = PyList_GetItem(retObjectX, i);
int res = 0;
PyArg_Parse(singleItem,"i",&res);//转换返回类型
ForecastVect.push_back(res);
//double item = PyFloat_AsDouble(singleItem);
//tmpVect.push_back(item);
}
qDebug()<<"test start";
qDebug()<append(set0);
series->setLabelsPosition(QAbstractBarSeries::LabelsInsideEnd); // 设置数据系列标签的位置于数据柱内测上方
series->setLabelsVisible(true); // 设置显示数据系列标签
QChart *chart = new QChart();
chart->addSeries(series);
chart->setTitle("forecast task number");
chart->setAnimationOptions(QChart::SeriesAnimations);
QBarCategoryAxis *axisX = new QBarCategoryAxis();
axisX->append(categories);
chart->addAxis(axisX, Qt::AlignBottom);
series->attachAxis(axisX);
QValueAxis *axisY = new QValueAxis();
chart->addAxis(axisY, Qt::AlignLeft);
series->attachAxis(axisY);
chart->legend()->setVisible(true);
chart->legend()->setAlignment(Qt::AlignBottom);
ui->widgetBar->setChart(chart);
}
void Widget::connectSQL()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("D:\\Djangoproj\\myWebTest\\db.sqlite3");
if (!db.open())
{
qDebug() << "open error";
}
else
{
qDebug()<<"ok";
}
SQLhandler();
db.close();
}
void Widget::SQLhandler()
{
QSqlQuery sql_query;
//qDebug()< week;
week.insert("周日",0);
week.insert("周一",1);
week.insert("周二",2);
week.insert("周三",3);
week.insert("周四",4);
week.insert("周五",5);
week.insert("周六",6);
//qDebug()<ck_ONOFF->font();
font.setBold(checked);
ui->ck_ONOFF->setFont(font);
ui->pushButton->setEnabled(true);
bl_addML = checked;
qDebug()<pushButton->setEnabled(false);
// 根据checkbox来选择带新增预测的数据或不带新增预测的数据
if (bl_addML)
{
CalculateTaskNum(ReviewPhase,DateInfo);
}
else
{
CalculateTaskNum(ReviewPhasePrevCopy,DateInfoPrevCopy);
}
ShowBar();
}
void Widget::CalculateTaskNum(const QVector &vReviewPhase,const QVector &vDateInfo)
{
int i;
CalCnt.clear();
for(i=0;i<14;i++)
{
CalCnt.append(0);
}
int index=0;
for(auto iphase:vReviewPhase)
{
int diff = 0;
int j=0;
/* change Datetime string to Data */
QDate tempDate = QDateTime::fromString(vDateInfo[index], "yyyy-MM-dd hh:mm:ss").date();
diff = curDate.daysTo(tempDate);
if(diff>=0 && diff<14)
{
/* add the default review date */
CalCnt[diff]++;
j=iphase+1; /* TBD */
/* accumulation for each phase while diff<15 */
while(diff<14 && j<6)
{
diff=diff+myRule[j++];
if(diff>=0 && diff<14)
{
CalCnt[diff]++;
}
}
}
else
{
j=iphase++;
/* some item didn't review on time, so is minus value */
while(diff<14 && diff>=0 && j<6)
{
diff=diff+myRule[j++];
if(diff>0 && diff<14)
{
CalCnt[diff]++;
}
}
}
/* next item */
index++;
}
}
void Widget::on_cb_rangeselect_currentIndexChanged(const QString &arg1)
{
//Q_UNUSED(arg1)
if(arg1=="one week")
{
showdays = 7;
}
else
{
showdays = 14;
}
ui->pushButton->setEnabled(true);
}