C++Python时空大数据

python预测数量及QT混合编程--Apple的学习笔记

2019-11-17  本文已影响0人  applecai

一,前言:

在我上一篇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文件中添加。

七,学到的技术总结

  1. QT c++和python的混合编程技能。
  2. 复习了机器学习中的朴素贝叶斯。
  3. QT Vector的copy用<<即可。
  4. 掌握了datetime的各种转换。
  5. 学习了python collections进行归类的字典输出。

八,github源码上传

https://github.com/AppleCai/taskForecast

九,运行效果图

结果.png

十,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()<<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); // 设置数据系列标签的位置于数据柱内测上方
    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()<<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];  //周几转为数字下标,从而可以从ForecastVect读取预测新学任务数

    int cnt=0;
    int i;
    for (i=1;i<14;i++)  // 当天新增的不进行预测,对2周内的后13天进行新增预测
    {
        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")]];
        // 将新增预测项数量添加到数据库中
        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);
    // 根据checkbox来选择带新增预测的数据或不带新增预测的数据
    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);
}
上一篇 下一篇

猜你喜欢

热点阅读