一妇多,前言:
在我上一篇blog QChart任務(wù)數(shù)預(yù)測項目實戰(zhàn)--Apple的學(xué)習(xí)筆記 中有一個python預(yù)測任務(wù),今天完成了并且進行QT c++及python混合編程后的集成写半。
二吏恭,功能:
要進行預(yù)測每天會新學(xué)習(xí)多少項內(nèi)容惠豺。然后繼續(xù)按艾賓浩斯曲線來處理。
三徒仓,思路分析:
哪些先分析下數(shù)據(jù)有什么特征腐碱,就會發(fā)現(xiàn)每天學(xué)習(xí)數(shù)量幾乎都少于10項。然后周末或周一新學(xué)習(xí)的數(shù)量會筆記多掉弛。周五新學(xué)習(xí)的數(shù)量會比較少症见。這是我的個人規(guī)律,周末不上班殃饿,所以學(xué)習(xí)數(shù)量可以多些谋作,周五一般就想休息了。
四乎芳,數(shù)學(xué)建模:
這個不屬于線性回歸遵蚜,屬于數(shù)據(jù)分類問題。那么預(yù)測每天會新學(xué)習(xí)多少項內(nèi)容的數(shù)學(xué)模型就簡化為如下:
預(yù)測周一的學(xué)習(xí)數(shù)量奈惑,周二的學(xué)習(xí)數(shù)量一直到周日的學(xué)習(xí)數(shù)量吭净,而且數(shù)組范圍為【1,10】。
機器學(xué)習(xí)里面首先想到樸素貝葉斯肴甸,由于此模型都沒有什么條件概率寂殉。所以又簡化為了計算周一出現(xiàn)[0,10]中哪個概率最大,則預(yù)測出將來的周一新學(xué)習(xí)項的數(shù)量原在。同理去推導(dǎo)周二到周日新學(xué)習(xí)的數(shù)量友扰。
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()
輸出結(jié)果
[5, 3]
代表周一預(yù)測新學(xué)習(xí)數(shù)量加5,周二加3庶柿。
五村怪,總結(jié)
由于我是2019-10-01開始使用這套系統(tǒng)的,所以當(dāng)前的訓(xùn)練數(shù)據(jù)就比較少浮庐,不準(zhǔn)確实愚。我的概率在某個星期n計算會發(fā)現(xiàn)都是一樣的,在這樣的情況下使用的是最大值就不太準(zhǔn)兔辅。
六,遇到的問題記錄
1.解決了python37_d無法打開的問題击喂,自己再copy一個然后重命名為_d.lib即可维苔。
2.Py_IsInitialized報錯,需要按網(wǎng)上說的修改python的include中的一個頭文件懂昂。
3.添加python模塊lib的方法可以右擊工程添加介时,也可以手工添加,最后用的是手工在pro文件中添加。
七沸柔,學(xué)到的技術(shù)總結(jié)
- QT c++和python的混合編程技能循衰。
- 復(fù)習(xí)了機器學(xué)習(xí)中的樸素貝葉斯。
- QT Vector的copy用<<即可褐澎。
- 掌握了datetime的各種轉(zhuǎn)換会钝。
- 學(xué)習(xí)了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] # 周日俭正,周一~周六每天新學(xué)的任務(wù)數(shù)
def connectUserDb():
con = sqlite3.connect(r'D:\Djangoproj\myWebTest\db.sqlite3')
return con
def queryUserRecords(con):
mytemplist = []
# 因為我的django工程師10月初做的奸鬓,所以從2019年10月1日后的數(shù)據(jù)算是有效的。然后開始統(tǒng)計
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])
# 對每一相同日期歸類串远,以字典顯示{日期:出現(xiàn)次數(shù)}
res = Counter(mytemplist)
print(res)
for key in res:
# 先將str轉(zhuǎn)成datatime格式后再轉(zhuǎn)為周幾
anyday = datetime.strptime(key, '%Y-%m-%d').strftime("%w") # key為日期字符串,做處理
tempnum = res[key]
# 預(yù)測的每天新增學(xué)習(xí)數(shù)量(即出現(xiàn)次數(shù))不超過10項儿惫,超過10則用10代表
if (tempnum>10):
tempnum = 10
mydatelist[int(anyday)].append(tempnum) # 將日期轉(zhuǎn)為周幾澡罚,并將出現(xiàn)次數(shù)copy到數(shù)組。
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: # 若出現(xiàn)次數(shù)相同姥闪,則選擇字?jǐn)?shù)最大的值作為預(yù)測性學(xué)習(xí)數(shù)量
maxNum = mydatelist[date].count(i)
useValue[date] =i
print (useValue)
def maintask():
connect=connectUserDb() # 連接數(shù)據(jù)庫
queryUserRecords(connect) # 查詢曾經(jīng)學(xué)習(xí)的記錄始苇,并且處理數(shù)據(jù)獲得每天(周一~周日)新學(xué)習(xí)的數(shù)量
forecast() # 進行機器分類學(xué)習(xí),在0-10之前出現(xiàn)最大的概率
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";
}
// 加載函數(shù)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腳本返回數(shù)據(jù)
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);//轉(zhuǎn)換返回類型
ForecastVect.push_back(res);
//double item = PyFloat_AsDouble(singleItem);
//tmpVect.push_back(item);
}
qDebug()<<"test start";
qDebug()<<ForecastVect;
qDebug()<<"test end";
Py_Finalize();
}
Widget::~Widget()
{
delete ui;
}
void Widget::ShowBar()
{
QBarSet *set0 = new QBarSet("taskNum");
QStringList categories;
int i;
for(i=0;i<showdays;i++)
{
*set0<< CalCnt[i];
categories<<curDate.addDays(i).toString("MMdd");
}
QBarSeries *series = new QBarSeries();
series->append(set0);
series->setLabelsPosition(QAbstractBarSeries::LabelsInsideEnd); // 設(shè)置數(shù)據(jù)系列標(biāo)簽的位置于數(shù)據(jù)柱內(nèi)測上方
series->setLabelsVisible(true); // 設(shè)置顯示數(shù)據(jù)系列標(biāo)簽
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()<<QString("select phase,review_date from myfile_reviewInfo where phase<8 and review_date<'%1'").arg(lastDate.toString("yyyy-MM-dd"));
QString select_sql = QString("select phase,review_date from myfile_reviewInfo where phase<8 and review_date<'%1'").arg(lastDate.toString("yyyy-MM-dd"));
sql_query.prepare(select_sql);
if(!sql_query.exec())
{
qDebug()<<sql_query.lastError();
}
else
{
while(sql_query.next())
{
ReviewPhase.append(sql_query.value("phase").toInt());
DateInfo.append(sql_query.value("review_date").toString());
}
}
// copy向量
ReviewPhasePrevCopy<<ReviewPhase;
DateInfoPrevCopy<<DateInfo;
}
void Widget::addmyForecast()
{
//QString curDay = curDate.toString("ddd");
QMap<QString, int> week;
week.insert("周日",0);
week.insert("周一",1);
week.insert("周二",2);
week.insert("周三",3);
week.insert("周四",4);
week.insert("周五",5);
week.insert("周六",6);
//qDebug()<<week[curDay]; //周幾轉(zhuǎn)為數(shù)字下標(biāo),從而可以從ForecastVect讀取預(yù)測新學(xué)任務(wù)數(shù)
int cnt=0;
int i;
for (i=1;i<14;i++) // 當(dāng)天新增的不進行預(yù)測避归,對2周內(nèi)的后13天進行新增預(yù)測
{
QDate nextDate = curDate.addDays(i);
QString tempstr=QString("%1 %2").arg(nextDate.toString("yyyy-MM-dd")).arg("20:00:00");
cnt=ForecastVect[week[nextDate.toString("ddd")]];
// 將新增預(yù)測項數(shù)量添加到數(shù)據(jù)庫中
DateInfo.insert(DateInfo.begin(),cnt,tempstr);
ReviewPhase.insert(ReviewPhase.begin(),cnt,0);
}
qDebug()<<DateInfo;
}
void Widget::on_ck_ONOFF_clicked(bool checked)
{
QFont font=ui->ck_ONOFF->font();
font.setBold(checked);
ui->ck_ONOFF->setFont(font);
ui->pushButton->setEnabled(true);
bl_addML = checked;
qDebug()<<bl_addML;
}
void Widget::on_pushButton_clicked()
{
ui->pushButton->setEnabled(false);
// 根據(jù)checkbox來選擇帶新增預(yù)測的數(shù)據(jù)或不帶新增預(yù)測的數(shù)據(jù)
if (bl_addML)
{
CalculateTaskNum(ReviewPhase,DateInfo);
}
else
{
CalculateTaskNum(ReviewPhasePrevCopy,DateInfoPrevCopy);
}
ShowBar();
}
void Widget::CalculateTaskNum(const QVector<int> &vReviewPhase,const QVector<QString> &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);
}