未分类

Flutter的RSA加密(支持modules和exponent

import ‘dart:io’;

import ‘package:encrypt/encrypt.dart’;

import ‘package:flutter/services.dart’ show rootBundle;

import ‘package:pointycastle/asymmetric/api.dart’;

class EncryptTool {

  ///  加密

  static encryption(content) async {

    final parser = RSAKeyParser();

    String publicKeyString =

        await rootBundle.loadString(‘assets/rsa/public.pem’);

    print(‘$publicKeyString’); // 注意这一行的输出

    final mpublicKey = parser.parse(publicKeyString);

    var publicKey = RSAPublicKey(mpublicKey.modulus!, mpublicKey.exponent!);

    final encrypter = Encrypter(RSA(publicKey: publicKey));

    final res = encrypter.encrypt(content).base64;

    print(“encryption data:”);

    print(encryption);

    return res;

  }

}

Flutter iOS 调试总是 Lost connection to device 解决办法

接iOS真机进行调试的时候,出现如下问题:

解决方法如下:

在终端运行 brew upgrade --fetch-HEAD usbmuxd

另外一种可能性就是你的电脑剩余空间不足,,也会导致该问题。。

作者:Tobesky
链接:https://www.jianshu.com/p/1d05ae840ce6
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

MySQL 数据库定时备份的几种方式(非常全面)

在操作数据过程中,可能会导致数据错误,甚至数据库奔溃,而有效的定时备份能很好地保护数据库。本篇文章主要讲述了几种方法进行 MySQL 定时备份数据库。

一. mysqldump命令备份数据

在MySQL中提供了命令行导出数据库数据以及文件的一种方便的工具mysqldump,我们可以通过命令行直接实现数据库内容的导出dump,首先我们简单了解一下mysqldump命令用法:

#MySQLdump常用
mysqldump -u root -p --databases 数据库1 数据库2 > xxx.sql

二. mysqldump常用操作示例

1.备份全部数据库的数据和结构

mysqldump -uroot -p123456 -A > /data/mysqlDump/mydb.sql

2.备份全部数据库的结构(加 -d 参数)

mysqldump -uroot -p123456 -A -d > /data/mysqlDump/mydb.sql

3.备份全部数据库的数据(加 -t 参数)

mysqldump -uroot -p123456 -A -t > /data/mysqlDump/mydb.sql

4.备份单个数据库的数据和结构(,数据库名mydb)

mysqldump -uroot-p123456 mydb > /data/mysqlDump/mydb.sql

5. 备份单个数据库的结构

mysqldump -uroot -p123456 mydb -d > /data/mysqlDump/mydb.sql

6. 备份单个数据库的数据

mysqldump -uroot -p123456 mydb -t > /data/mysqlDump/mydb.sql

7. 备份多个表的数据和结构(数据,结构的单独备份方法与上同)

mysqldump -uroot -p123456 mydb t1 t2 > /data/mysqlDump/mydb.sql

8. 一次备份多个数据库

mysqldump -uroot -p123456 --databases db1 db2 > /data/mysqlDump/mydb.sql

三. 还原 MySQL 备份内容

有两种方式还原,第一种是在 MySQL 命令行中,第二种是使用 SHELL 行完成还原

1.在系统命令行中,输入如下实现还原:

mysql -uroot -p123456 < /data/mysqlDump/mydb.sql

2.在登录进入mysql系统中,通过source指令找到对应系统中的文件进行还原:

mysql> source /data/mysqlDump/mydb.sql

在 Linux中,通常使用BASH脚本对需要执行的内容进行编写,加上定时执行命令crontab实现日志自动化生成。

以下代码功能就是针对mysql进行备份,配合crontab,实现备份的内容为近一个月(31天)内的每天的mysql数据库记录。

编写BASH维护固定数量备份文件

在Linux中,使用vi或者vim编写脚本内容并命名为:mysql_dump_script.sh

#!/bin/bash

#保存备份个数,备份31天数据
number=31
#备份保存路径
backup_dir=/root/mysqlbackup
#日期
dd=`date +%Y-%m-%d-%H-%M-%S`
#备份工具
tool=mysqldump
#用户名
username=root
#密码
password=TankB214
#将要备份的数据库
database_name=edoctor

#如果文件夹不存在则创建
if [ ! -d $backup_dir ];
then     
    mkdir -p $backup_dir;
fi

#简单写法 mysqldump -u root -p123456 users > /root/mysqlbackup/users-$filename.sql
$tool -u $username -p$password $database_name > $backup_dir/$database_name-$dd.sql

#写创建备份日志
echo "create $backup_dir/$database_name-$dd.dupm" >> $backup_dir/log.txt

#找出需要删除的备份
delfile=`ls -l -crt $backup_dir/*.sql | awk '{print $9 }' | head -1`

#判断现在的备份数量是否大于$number
count=`ls -l -crt $backup_dir/*.sql | awk '{print $9 }' | wc -l`

if [ $count -gt $number ]
then
  #删除最早生成的备份,只保留number数量的备份
  rm $delfile
  #写删除文件日志
  echo "delete $delfile" >> $backup_dir/log.txt
fi

如上代码主要含义如下:

1.首先设置各项参数,例如number最多需要备份的数目,备份路径,用户名,密码等。

2.执行mysqldump命令保存备份文件,并将操作打印至同目录下的log.txt中标记操作日志。

3.定义需要删除的文件:通过ls命令获取第九列,即文件名列,再通过实现定义操作时间最晚的那个需要删除的文件。

4.定义备份数量:通过ls命令加上wc -l统计以sql结尾的文件的行数。

5.如果文件超出限制大小,就删除最早创建的sql文件

使用crontab定期执行备份脚本

在 Linux 中,周期执行的任务一般由cron这个守护进程来处理[ps -ef|grep cron]。cron读取一个或多个配置文件,这些配置文件中包含了命令行及其调用时间。 cron的配置文件称为“crontab”,是“cron table”的简写。

cron服务

cron是一个 Liunx 下 的定时执行工具,可以在无需人工干预的情况下运行作业。

service crond start    //启动服务
service crond stop     //关闭服务
service crond restart  //重启服务
service crond reload   //重新载入配置
service crond status   //查看服务状态 

crontab语法

crontab命令用于安装、删除或者列出用于驱动cron后台进程的表格。用户把需要执行的命令序列放到crontab文件中以获得执行。每个用户都可以有自己的crontab文件。/var/spool/cron下的crontab文件不可以直接创建或者直接修改。该crontab文件是通过crontab命令创建的。

在crontab文件中如何输入需要执行的命令和时间。该文件中每行都包括六个域,其中前五个域是指定命令被执行的时间,最后一个域是要被执行的命令。 每个域之间使用空格或者制表符分隔。

格式如下:

minute hour day-of-month month-of-year day-of-week commands 
合法值 00-59 00-23 01-31 01-12 0-6 (0 is sunday) 

除了数字还有几个个特殊的符号就是"*"、"/"和"-"、",",*代表所有的取值范围内的数字,"/"代表每的意思,"/5"表示每5个单位,"-"代表从某个数字到某个数字,","分开几个离散的数字。

-l 在标准输出上显示当前的crontab。 
-r 删除当前的crontab文件。 
-e 使用VISUAL或者EDITOR环境变量所指的编辑器编辑当前的crontab文件。当结束编辑离开时,编辑后的文件将自动安装。 

创建cron脚本

  • 第一步:写cron脚本文件,命名为mysqlRollBack.cron。 15,30,45,59 * * * * echo “xgmtest…..” >> xgmtest.txt 表示,每隔15分钟,执行打印一次命令
  • 第二步:添加定时任务。执行命令 “crontab crontest.cron”。搞定
  • 第三步:”crontab -l” 查看定时任务是否成功或者检测/var/spool/cron下是否生成对应cron脚本

注意:这操作是直接替换该用户下的crontab,而不是新增

定期执行编写的定时任务脚本(记得先给shell脚本执行权限)

0 2 * * * /root/mysql_backup_script.sh

随后使用crontab命令定期指令编写的定时脚本

crontab mysqlRollback.cron

再通过命令检查定时任务是否已创建:

附 crontab 的使用示例:

1.每天早上6点

0 6 * * * echo "Good morning." >> /tmp/test.txt //注意单纯echo,从屏幕上看不到任何输出,因为cron把任何输出都email到root的信箱了。

2.每两个小时

0 */2 * * * echo "Have a break now." >> /tmp/test.txt

3.晚上11点到早上8点之间每两个小时和早上八点

0 23-7/2,8 * * * echo "Have a good dream" >> /tmp/test.txt

4.每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点

0 11 4 * 1-3 command line

5.1月1日早上4点

0 4 1 1 * command line SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root //如果出现错误,或者有数据输出,数据作为邮件发给这个帐号 HOME=/

6.每小时执行/etc/cron.hourly内的脚本

01 * * * * root run-parts /etc/cron.hourly

7.每天执行/etc/cron.daily内的脚本

02 4 * * * root run-parts /etc/cron.daily

8.每星期执行/etc/cron.weekly内的脚本

22 4 * * 0 root run-parts /etc/cron.weekly

9.每月去执行/etc/cron.monthly内的脚本

42 4 1 * * root run-parts /etc/cron.monthly

注意: “run-parts” 这个参数了,如果去掉这个参数的话,后面就可以写要运行的某个脚本名,而不是文件夹名。

10.每天的下午4点、5点、6点的5 min、15 min、25 min、35 min、45 min、55 min时执行命令。

5,15,25,35,45,55 16,17,18 * * * command

11.每周一,三,五的下午3:00系统进入维护状态,重新启动系统。

00 15 * * 1,3,5 shutdown -r +5

12.每小时的10分,40分执行用户目录下的innd/bbslin这个指令:

10,40 * * * * innd/bbslink

13.每小时的1分执行用户目录下的bin/account这个指令:

1 * * * * bin/account

以下是我的测试每分钟的截图效果,其对应代码如下:

* * * * * /root/mysql_backup_script.sh

效果截图:

其中的log.txt记录备份的操作详细日志:

upstream prematurely closed connection while reading response header from upstream,

nginx 502报错

错误信息:upstream prematurely closed connection while reading response header from upstream,

错误现象:nginx正常接收请求,正常调用后台接口,正常获取接口返回信息,但是请求已经中断

解决方案:

location / {

proxy_http_version 1.1;

    proxy_set_header Connection “Keep-Alive”;

}

原因:

nginx默认采用http1.0从后端获取响应返还给客户端,但是HTTP1.0不支持keepalive;

proxy_set_header Connection默认close:通知后端服务器主动关闭连接,这样会导致任何一个客户端的请求都在后端服务器上产生了一个TIME-WAIT状态的连接

mac提示Insecure world writable解决

问题起因是 给同事开了一下分享,但是目录实在 Users/xxx 下,给这个目录开了“客人”读写权限。因此提示 Insecure world writable dir /Users/xxx/yyy

解决办法 就是 把 群组和其他人对这个目录/文件的 读写权限去掉

chmod go-rw /Users/xxx/yyy

 

excel 表格如何旋转?列转换成行

在EXCEL中,表格怎么从列旋转到行,也就是列转换成行。本文分享其中的操作方法。

excel 表格如何旋转?列转换成行

工具/原料

  • EXCEL 2013

方法/步骤

  1. 准备一张表格;如图中所示,

    接下来,我们要先把表格所有数据都全选中,包括文字、数值。

    excel 表格如何旋转?列转换成行
    excel 表格如何旋转?列转换成行
  2. 然后,操作复制;

    复制方法有三种;

    方法一是,鼠标在选区上右击,弹出菜单,再点:复制;

    excel 表格如何旋转?列转换成行
  3. 方法二是,

    在开始选项卡这里,找到复制的按钮,如下图所示。

    点击一下,即可把表格复制;

    方法三,按下快捷键:CTRL+C

    excel 表格如何旋转?列转换成行
  4. 复制好数值后,选区外围呈浮动的蚂蚁线。

    然后,鼠标在要粘贴的单元格上点击一下,选中这个单元格。

    excel 表格如何旋转?列转换成行
  5. 鼠标放在单元格上右击,弹出菜单中点:选择性粘贴

    excel 表格如何旋转?列转换成行
  6. 鼠标点:选择性粘贴;

    在右侧又弹出一个列表;

    在列表中找到:置换

    excel 表格如何旋转?列转换成行
  7. 看,表格已旋转过来,列变行了。

    excel 表格如何旋转?列转换成行

WIN10怎么更改电脑无线网络连接的优先级排序

当电脑在同一个地方连接多个无线后,会默认将这些连接过的无线网进行排序,去自动连接到网络,那么怎么样将某个连接的WIFI放到最前面,也就是将这些WIFI排序,小编介绍下流程。

WIN10怎么更改电脑无线网络连接的优先级排序
工具/原料
无线网络
电脑
方法/步骤
1
将WIN10系统电脑的设置打开后,显示设置界面,点击其中的网络和Intenet模块如下图指示方法。

WIN10怎么更改电脑无线网络连接的优先级排序
WIN10怎么更改电脑无线网络连接的优先级排序
2
打开网络设置界面,默认到了状态分类下,往下翻,找到倒数第二个,网络和共享中心,点击它。

WIN10怎么更改电脑无线网络连接的优先级排序
3
显示此时电脑的所有有线和无线网络连接情况,点击无线网卡连接的网络,小编是9-301,见下图。

WIN10怎么更改电脑无线网络连接的优先级排序
4
弹出WLAN状态窗口,鼠标点击左下角的属性按钮。

WIN10怎么更改电脑无线网络连接的优先级排序
5
弹出无线网络的具体属性情况,选择到IPV4,目前IPV6尚未普及,所以多数都是V4版本。

WIN10怎么更改电脑无线网络连接的优先级排序
6
选好后,属性变亮可以选择,点击属性。

WIN10怎么更改电脑无线网络连接的优先级排序
7
接着显示该网络的IP地址和网关等情况,点击右下角的高级按钮。

WIN10怎么更改电脑无线网络连接的优先级排序
8
在高级界面中,底部的自动跃点是被勾选的,我们将其取消后,输入数字1,这样,该网络的优先级是最高的。

完成后点击确定,这样就将该无线网络顺序提高到第一位啦。

WIN10怎么更改电脑无线网络连接的优先级排序
WIN10怎么更改电脑无线网络连接的优先级排序

用Rasa NLU构建自己的中文NLU系统

代码在 https://github.com/crownpku/rasa_nlu_chi

自然语言理解(NLU)系统是问答系统、聊天机器人等更高级应用的基石。基本的NLU工具,包括实体识别和意图识别两个任务。

已有的NLU工具,大多是以服务的方式,通过调用远程http的restful API来对目标语句进行解析完成上述两个任务。这样的工具有Google的API.ai, Microsoft的Luis.ai, Facebook的Wit.ai等。刚刚被百度收购的Kitt.ai除了百度拿出来秀的语音唤醒之外,其实也有一大部分工作是在NLU上面,他们很有启发性的的Chatflow就包含了一个自己的NLU引擎。

(话说,现在.ai的域名都好贵呢…其实是安圭拉的国家域名,这个小岛就这么火了…)

以上这些工具,一边为用户提供NLU的服务,一边也通过用户自己上传的大量标注和非标注数据不断训练和改进自己的模型。而对于数据敏感的用户来说,开源的NLU工具如Rasa.ai就为我们打开了另一条路。更加重要的是,这样的开源工具可以本地部署,自己针对实际需求训练和调整模型,据说对一些特定领域的需求效果要比那些通用的在线NLU服务还要好很多。

我们在这里就简单介绍使用Rasa NLU构建一个本地部署的特定领域的中文NLU系统。

Rasa NLU本身是只支持英文和德文的。中文因为其特殊性需要加入特定的tokenizer作为整个流水线的一部分。我加入了jieba作为我们中文的tokenizer,这个适用于中文的rasa NLU的版本代码在github上。

语料获取及预处理

Rasa NLU的实体识别和意图识别的任务,需要一个训练好的MITIE的模型。这个MITIE模型是非监督训练得到的,类似于word2vec中的word embedding。

要训练这个MITIE模型,我们需要一个规模比较大的中文语料。最好的方法是用对应自己需求的语料,比如做金融的chatbot就多去爬取些财经新闻,做医疗的chatbot就多获取些医疗相关文章。

我使用的是awesome-chinese-nlp中列出的中文wikipedia dump和百度百科语料。其中关于wikipedia dump的处理可以参考这篇帖子

仅仅获取语料还不够,因为MITIE模型训练的输入是以词为单位的。所以要先进行分词,我们使用结巴分词。

安装结巴分词:

$ pip install jieba

将一个语料文件分词,以空格为分隔符:

$ python -m jieba -d " " ./test > ./test_cut

MITIE模型训练

我们把所有分好词的语料文件放在同一个文件路径下。接下来我们要训练MITIE模型。

首先将MITIE clone下来:

$ git clone https://github.com/mit-nlp/MITIE.git

我们要使用的只是MITIE其中wordrep这一个工具。我们先build它。

$ cd MITIE/tools/wordrep
$ mkdir build
$ cd build
$ cmake ..
$ cmake --build . --config Release

然后训练模型,得到total_word_feature_extractor.dat。注意这一步训练会耗费几十GB的内存,大概需要两到三天的时间。。。

$ ./wordrep -e /path/to/your/folder_of_cutted_text_files

我用中文wikipedia和百度百科语料生成了一个total_word_feature_extractor_chi.dat,分享如下。

链接:https://pan.baidu.com/s/1kNENvlHLYWZIddmtWJ7Pdg 密码:p4vx

对于一些比较general的NLU使用场景,这个应该是够用了。

构建rasa_nlu语料和模型

  • 将rasa_nlu_chi clone下来并安装:
$ git clone https://github.com/crownpku/rasa_nlu_chi.git
$ cd rasa_nlu_chi
$ python setup.py install
  • 构建尽可能多的示例数据来做意图识别和实体识别的训练数据:

data/examples/rasa/demo-rasa_zh.json

格式是json,例子如下。’start’和’end’是实体对应在’text’中的起止index。

     {
        "text": "找个吃拉面的店",
        "intent": "restaurant_search",
        "entities": [
          {
            "start": 3,
            "end": 5,
            "value": "拉面",
            "entity": "food"
          }
        ]
      },
      {
        "text": "这附近哪里有吃麻辣烫的地方",
        "intent": "restaurant_search",
        "entities": [
          {
            "start": 7,
            "end": 10,
            "value": "麻辣烫",
            "entity": "food"
          }
        ]
      },
      {
        "text": "附近有什么好吃的地方吗",
        "intent": "restaurant_search",
        "entities": []
      },
      {
        "text": "肚子饿了,推荐一家吃放的地儿呗",
        "intent": "restaurant_search",
        "entities": []
      }

这里有个小bug,就是这个entity一定要刚刚好是text被jieba分词后其中的一个词。如果jieba分词的结果中分错了你设定的entity这个词就会报错。所以写这个示例数据的时候,要参考jieba对text的分词结果来写。

上述bug已解决。

  • 修改pipeline的设置

对于中文我们现在有两种pipeline:

使用 MITIE+Jieba:

[“nlp_mitie”, “tokenizer_jieba”, “ner_mitie”, “ner_synonyms”, “intent_classifier_mitie”]

这种方式训练比较慢,效果也不是很好,最后出现的intent也没有分数排序。

我们推荐使用下面的pipeline:

MITIE+Jieba+sklearn (sample_configs/config_jieba_mitie_sklearn.json):

[“nlp_mitie”, “tokenizer_jieba”, “ner_mitie”, “ner_synonyms”, “intent_featurizer_mitie”, “intent_classifier_sklearn”]

这里也可以看到Rasa NLU的工作流程。”nlp_mitie”初始化MITIE,”tokenizer_jieba”用jieba来做分词,”ner_mitie”和”ner_synonyms”做实体识别,”intent_featurizer_mitie”为意图识别做特征提取,”intent_classifier_sklearn”使用sklearn做意图识别的分类。

2017.11.16更新: 关于加入jieba自定义词典,暂时没有找到非常优雅的做法。现在的版本,需要用户把jieba自定义词典放到rasa_nlu_chi/jieba_userdict/下面。系统在训练和预测时都会自动寻找并导入jieba分词。

  • 训练Rasa NLU的模型
$ python -m rasa_nlu.train -c sample_configs/config_jieba_mitie_sklearn.json

这样就会生成一个类似model_20170714-195758的文件在 /models/your_project_name 的文件夹里。

如果config文件中没有project_name,模型会存储在默认的 /models/default 文件夹下。

搭建本地rasa_nlu服务

  • 启动rasa_nlu的后台服务:
python -m rasa_nlu.server -c sample_configs/config_jieba_mitie_sklearn.json
  • 打开一个新的terminal,我们现在就可以使用curl命令获取结果了, 举个例子:
$ curl -XPOST localhost:5000/parse -d '{"q":"我发烧了该吃什么药?", "project": "rasa_nlu_test", "model": "model_20170921-170911"}' | python -mjson.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   652    0   552  100   100    157     28  0:00:03  0:00:03 --:--:--   157
{
    "entities": [
        {
            "end": 3,
            "entity": "disease",
            "extractor": "ner_mitie",
            "start": 1,
            "value": "发烧"
        }
    ],
    "intent": {
        "confidence": 0.5397186422631861,
        "name": "medical"
    },
    "intent_ranking": [
        {
            "confidence": 0.5397186422631861,
            "name": "medical"
        },
        {
            "confidence": 0.16206323981749196,
            "name": "restaurant_search"
        },
        {
            "confidence": 0.1212448457737397,
            "name": "affirm"
        },
        {
            "confidence": 0.10333600028547868,
            "name": "goodbye"
        },
        {
            "confidence": 0.07363727186010374,
            "name": "greet"
        }
    ],
    "text": "我发烧了该吃什么药?"
}

Rasa UI界面

上面可以看到这种后台服务、前台curl的方式,其实已经可以代替之前提到的一大票云端的NLU服务了。

有热心的前端大牛还做了一个Rasa UI,提供Rasa的界面。理论上是要将前面提到的示例数据的添加、模型的训练以及服务的监控等等都做成一个漂亮的web界面。只是现在还开发的非常不完善,大部分的功能还都没有加进去。

有兴趣的朋友可以clone下来装一个试试。效果如下:

 

Rasa_NLU_Chi

Rasa NLU 是一个开源的、可本地部署并配套有语料标注工具(rasa-nlu-trainer)的自然语言理解框架。其本身是只支持英文和德文,中文因为其特殊性需要加入特定的 tokenizer 作为整个流水线的一部分,Rasa_NLU_Chi 作为 Rasa_NLU 的一个 fork 版本,加入了 jieba 作为中文的 tokenizer,实现了中文支持。

本篇即简单介绍基于 Rasa_NLU_Chi 构建一个本地部署的特定领域的中文 NLU 系统的过程和注意事项。

Why Rasa NLU

自然语言理解(NLU)系统是 chatbot 的基石,尽管使用正则或者模板匹配的方式也能在很多场景下实现一个简单的问答系统,但却缺乏泛化和学习的能力,而基于机器学习的 NLU 系统则可以举一反三不断学习改进模型从而获得越来越好的性能表现。

目前已有的 NLU 工具,大多是以服务的方式,通过调用远程 http 的 restful API 来对目标语句进行解析。包括 Google 的 API.ai、Microsoft 的 Luis.ai、Facebook 的 Wit.ai 等。这些 NLU 系统一边为用户提供NLU的服务,一边也通过用户自己上传的大量标注和非标注数据不断训练和改进自己的模型。对于数据敏感的用户来说,开源的 NLU 工具如 Rasa.ai 就为我们提供了另一种选择。而且这样的开源工具可以本地部署,针对实际需求训练和调整模型,甚至对一些特定领域的需求效果要比那些通用的在线 NLU 服务还要好。

Rasa Stack

Rasa Stack 包括 Rasa NLU 和 Rasa Core,前者负责进行语义理解(意图识别和槽值提取),而后者负责会话管理,控制跟踪会话并决定下一步要做什么,两者都使用了机器学习的方法可以从真实的会话数据进行学习;另外他们之间还相互独立,可以单独使用。

下图是一个简单的基于 Rasa 的 workflow 示意:

Pipeline

rasa nlu 支持不同的 Pipeline,其后端实现可支持 spaCy、MITIE、MITIE + sklearn 以及 tensorflow,其中 spaCy 是官方推荐的,另外值得注意的是从 0.12 版本后,MITIE 就被列入 Deprecated 了。

本例使用的 pipeline 为 MITIE+Jieba+sklearn, rasa nlu 的配置文件为 config_jieba_mitie_sklearn.yml 如下:

language: "zh"

pipeline:
- name: "nlp_mitie"
  model: "data/total_word_feature_extractor_zh.dat"  // 加载 mitie 模型
- name: "tokenizer_jieba"  // 使用 jieba 进行分词
- name: "ner_mitie"  // mitie 的命名实体识别
- name: "ner_synonyms"
- name: "intent_entity_featurizer_regex"
- name: "intent_featurizer_mitie"  // 特征提取
- name: "intent_classifier_sklearn" // sklearn 的意图分类模型

Preparation Work

由于在 pipeline 中使用了 MITIE,所以需要一个训练好的 MITIE 模型。MITIE 模型是非监督训练得到的,类似于 word2vec 中的 word embedding,需要大量的中文语料,由于训练这个模型对内存要求较高,并且耗时很长,这里直接使用了网友分享的中文 wikipedia 和百度百科语料生成的模型文件 total_word_feature_extractor_chi.dat,通过下面的百度网盘可以直接下载。

链接:https://pan.baidu.com/s/1kNENvlHLYWZIddmtWJ7Pdg 密码:p4vx

实际应用中,如果做某个特定领域的 NLU 并收集了很多该领域的语料,可以自己去训练 MITIE 模型,具体训练方法可以参考MITIE – Github

构建 rasa_nlu 语料

得到 MITIE 词向量模型以后便可以借助其训练 Rasa NLU 模型,这里需要使用标注好的数据来训练 rasa_nlu,标注的数据格式如下,Rasa 也很贴心的提供了数据标注平台rasa-nlu-trainer供用户标注数据。这里我们使用项目里提供的标注好的数据(demo-rasa_zh.json)直接进行训练。

[
    {
        "text": "我生病了,不知道去哪里看病",
        "intent": "medical_department",
        "entities": []
    },
    {
        "text": "头上烫烫的,感觉发烧了,该去看哪个诊所哪个科室好呢",
        "intent": "medical_department",
        "entities": [
          {
            "start": 8,
            "end": 10,
            "value": "发烧",
            "entity": "disease"
          }
        ]
    }

]

训练 rasa_nlu 模型

通过上面的准备工作,我们已经有了词向量模型 MITIE 和标注数据,接下来就可以直接按照下面的流程进行训练

$ source activate learn // 切换到之前创建的虚拟环境

$ git clone https://github.com/crownpku/Rasa_NLU_Chi.git // clone 源码

$ cd Rasa_NLU_Chi

$ python setup.py install  // 安装依赖

// 训练Rasa NLU的模型
$ python -m rasa_nlu.train -c sample_configs/config_jieba_mitie_sklearn.yml --data data/examples/rasa/demo-rasa_zh.json --path models

最后一步执行训练会得到一个模型文件如下所示,这个模型文件也是我们应用中进行意图识别和槽值提取直接使用到的模型,这一步可以离线进行训练,也可以在线实时训练。

测试验证

// 启动服务
$ python -m rasa_nlu.server -c sample_configs/config_jieba_mitie_sklearn.yml --path models

//测试服务
$ curl -XPOST localhost:5000/parse -d '{"q":"我感觉headache该吃什么药?", "project": "", "model": "model_20180912-202427"}' | python -mjson.tool

首先启动 Rasa NLU 服务,使用 curl 调用服务验证一下,可以看到如下结果,意图和实体都可以正确识别,同时还会给出识别的打分排序,便于我们观察和调整模型。

{
    "entities": [
        {
            "confidence": null,
            "end": 11,
            "entity": "disease",
            "extractor": "ner_mitie",
            "start": 3,
            "value": "headache"
        }
    ],
    "intent": {
        "confidence": 0.40319739542291566,
        "name": "medical"
    },
    "intent_ranking": [
        {
            "confidence": 0.40319739542291566,
            "name": "medical"
        },
        {
            "confidence": 0.22340213611408624,
            "name": "restaurant_search"
        },
        {
            "confidence": 0.18051898067667496,
            "name": "affirm"
        },
        {
            "confidence": 0.11803116503887297,
            "name": "goodbye"
        },
        {
            "confidence": 0.07485032274745018,
            "name": "greet"
        }
    ],
    "text": "\u6211\u611f\u89c9headache\u8be5\u5403\u4ec0\u4e48\u836f\uff1f"
}

注意事项

实践的过程中遇到了一些问题花了一些时间去解决,记录一下避免下次继续踩坑。

问题一

异常信息:

Exception: Not all required packages are installed. To use this pipeline, you need to install the missing dependencies. Please install sklearn

解决方法:

$pip install -U scikit-learn scipy sklearn-crfsuite

参考:https://github.com/RasaHQ/rasa_nlu/issues/660

量化回测框架Backtrader【2】-数据导入(附:Tushare介绍)

免责声明:本文不构成投资建议。投资有风险,入市须谨慎。

量化回测的第一步就是导入数据,Backtrader中称这个为data feeds,支持多种数据导入方式

  • 通用CSV格式
  • panda数据
  • Backtrader CSV Backtrader 为测试自创的格式,
  • 一系列的第三方数据包括(yahoo等)

由于后面两种方式暂时还不会用到,所以只介绍前面两种方式。

一,通用参数

由于所有的数据导入类都派生于同一个基类,所以所有的数据导入类都支持通用参数。

  • dataname (默认值: 无) 必须提供
    含义随数据类型(文件位置,代码,…)而异。
  • name (默认值: ‘’)
    用于绘图。 如果未指定,则会从数据名派生(例如:文件路径的最后一部分)
  • fromdate (默认值: 最早的时间)
    Python datetime对象,忽略最早时间之前的任何时间
  • todate (默认值: 最晚的时间)
    Python datetime对象,忽略最晚时间之后的任何时间
  • timeframe (默认值: TimeFrame.Days)
    时间间隔,可选值: TicksSecondsMinutesDaysWeeksMonths and Years
  • compression (默认值: 1)
    每个bar里面实际包含的bar数量(bar是时间的颗粒度,相当于k线图上的一个柱子),仅在数据重采样/回放中有效。
  • sessionstart (默认值: None)
    指示数据的会话开始时间。 可能被类用于诸如重采样之类的目的
  • sessionend (默认值: None)
    指示数据的会话结束时间。 可能被类用于诸如重采样之类的目的

二,通用CSV格式数据导入

函数名:GenericCSVData

独有参数:

  • dataname 数据文件名
  • datetime (默认值: 0) 日期数据所在列
  • time (默认值: -1) 时间数据所在列(-1代表没有)
  • open (默认值: 1) , high (默认值: 2), low (默认值: 3), close (默认值: 4), volume (默认值: 5), openinterest (默认值: 6)
    分别表示开盘,最高价,最低价,收盘价,交易量,持仓量所在列(-1代表没有)
  • nullvalue (默认值: float(‘NaN’))
    用来替换缺失值的值
  • dtformat (默认值: %Y-%m-%d %H:%M:%S)
    日期格式
  • tmformat (默认值: %H:%M:%S)
    时间格式

再举例子前先介绍一个可以获取股票行情数据的平台,tushare。

Tushare是一个免费、开源的python财经数据接口包。主要实现对股票等金融数据从数据采集清洗加工数据存储的过程,能够为金融分析人员提供快速、整洁、和多样的便于分析的数据,为他们在数据获取方面极大地减轻工作量,使他们更加专注于策略和模型的研究与实现上。考虑到Python pandas包在金融量化分析中体现出的优势,Tushare返回的绝大部分的数据格式都是pandas DataFrame类型,非常便于用pandas/NumPy/Matplotlib进行数据分析和可视化。当然,如果您习惯了用Excel或者关系型数据库做分析,您也可以通过Tushare的数据存储功能,将数据全部保存到本地后进行分析。应一些用户的请求,从0.2.5版本开始,Tushare同时兼容Python 2.x和Python 3.x,对部分代码进行了重构,并优化了一些算法,确保数据获取的高效和稳定。

我对比了一下网上其他的数据源,相对来说这个平台的数据还是比较齐全的,日线数据是免费的,对于入门级的基础研究也够用了,高级一点的数据可能就需要去赚积分了。具体可以看他们的官网

欢迎大家通过我的推荐去注册,谢谢!Tushare注册

下面举个从tushare获取日线数据的例子:

import tushare as ts
import pandas as pd

pro = ts.pro_api(token='your token id')
df = pro.daily(ts_code='000001.SZ', start_date='20110101', end_date='20210101').iloc[::-1]
df.to_csv('stock_data.csv', index=False )

tushare的pro版本是需要注册使用的,注册成功以后会获得一个token id,用你申请到的token id替换代码中的‘your token id’。

获取日线数据的api是pro.daily(), 参数:

  • ts_code:股票代码
  • start_date:数据开始日期
  • end_date:数据结束日期

返回的是一个pandas的dataframe。由于tushare返回的数据是时间反序的,即最新的日期在最前面,这跟BackTrader对数据的要求正好相反,所以用‘iloc[::-1]’使它颠倒一下顺序。最后一行代码就是调用pandas的转存为csv的接口保存为csv文件供以后使用。

最终应该可以在notebook的根目录(如果运行在jupyter上)下生成名为‘stock_data.csv’的中国平安(股票代码:000001.SZ)从20110101到20210101的日线数据文件。

接下来我们就可以用这个数据文件测试BackTrader的数据导入接口。

from datetime import datetime
import backtrader as bt
import backtrader.feeds as btfeeds

class SmaCross(bt.SignalStrategy):
    def __init__(self):
        sma1, sma2 = bt.ind.SMA(period=10), bt.ind.SMA(period=30)
        crossover = bt.ind.CrossOver(sma1, sma2)
        self.signal_add(bt.SIGNAL_LONG, crossover)

cerebro = bt.Cerebro()
cerebro.addstrategy(SmaCross)

data = btfeeds.GenericCSVData(
    dataname='stock_data.csv',
    fromdate=datetime(2011, 1, 1),
    todate=datetime(2012, 12, 31),
    nullvalue=0.0,
    dtformat=('%Y%m%d'),
    datetime=1,
    open=2,
    high=3,
    low=4,    
    close=5,
    volume=9,
    openinterest=-1
)

cerebro.adddata(data)

cerebro.run()
cerebro.plot(iplot=False)

在上一讲的代码的基础上修改了数据导入的接口

上图显示了我们从tushare下载到的数据,

日期格式是‘年月日’且没有分割,所以dtformat为’%Y%m%d’

‘datetime’,‘open’,‘high’,‘low’,‘close’,‘volume’分别是对应的列序(第一列的列序为0)

如果运行没有问题的话应该会输出如下的图表

三,panda数据导入

独有参数:

  • nocase (默认值:True) 匹配列名时不区分大小写

参数dataname 传入Pandas DataFrame变量

参数datetimeopen , high low close volumeopeninterest 用列名或列序指定

如果索引列是日期,则参数datetime可以不提供

例子如下:

from datetime import datetime
import backtrader as bt
import backtrader.feeds as btfeeds
import tushare as ts
import pandas as pd

class SmaCross(bt.SignalStrategy):
    def __init__(self):
        sma1, sma2 = bt.ind.SMA(period=10), bt.ind.SMA(period=30)
        crossover = bt.ind.CrossOver(sma1, sma2)
        self.signal_add(bt.SIGNAL_LONG, crossover)

cerebro = bt.Cerebro()
cerebro.addstrategy(SmaCross)

pro = ts.pro_api(token='936d1029be68a59a3e77eeb9e4eb1ea3c36502bd4b4bf9e1aae91bd8')
df = pro.daily(ts_code='000001.SZ', start_date='20110101', end_date='20210101').iloc[::-1]
df.trade_date=pd.to_datetime(df.trade_date) #由于trade_date是字符串,BackTrader无法识别,需要转一下
data = btfeeds.PandasData(
    dataname=df,
    fromdate=datetime(2011, 1, 1),
    todate=datetime(2012, 12, 31),
    datetime='trade_date',
    open='open',
    high='high',
    low='low',    
    close='close',
    volume='vol',
    openinterest=-1
)

cerebro.adddata(data)

cerebro.run()
cerebro.plot(iplot=False)

由于tushare返回的就是pandas的dataframe,所以这里可以直接使用,只是trade_date列需要转成datatime格式,输出跟上个例子一样就不重复贴了。

四,导入扩展数据类别

BackTrader的data feeds默认导入的数据类别是datetimeopen , high low close volumeopeninterest。除了这些基本的数据,我们可能会使用其他的数据类别作为策略的依据,BackTrader也支持数据类别的扩展,方法如下:

from backtrader.feeds import GenericCSVData

class GenericCSV_extend(GenericCSVData):

    # 添加change数据
    lines = ('change',)

    # 添加参数,由于openinterest默认是index 7 所以我们默认index 8
    params = (('change', 8),)

从GenericCSVData类继承创建新类,新类里添加lines(下一讲会介绍这个lines),再为这个数据类别添加新的参数。使用这个新创的类就可以导入新的数据了,示例如下:

from datetime import datetime
import backtrader as bt
from backtrader.feeds import GenericCSVData
import backtrader.indicators as btind

class GenericCSV_extend(GenericCSVData):

    # 添加change数据
    lines = ('change',)

    # 添加参数,由于openinterest默认是index 7 所以我们默认index 8
    params = (('change', 8),)


class SmaCross(bt.SignalStrategy):
    def __init__(self):
        sma1, sma2 = bt.ind.SMA(period=10), bt.ind.SMA(period=30)        
        crossover = bt.ind.CrossOver(sma1, sma2)
        self.signal_add(bt.SIGNAL_LONG, crossover)
        
        #为了显示新加的change添加一个change的移动均值
        btind.SMA(self.data.change, period=1, subplot=True)

cerebro = bt.Cerebro()
cerebro.addstrategy(SmaCross)

data = GenericCSV_extend(
    dataname='stock_data.csv',

    fromdate=datetime(2011, 1, 1),
    todate=datetime(2012, 12, 31),

    nullvalue=0.0,

    dtformat=('%Y%m%d'),

    datetime=1,
    open=2,
    high=3,
    low=4,    
    close=5,   
    change=7, #新导入数据change
    volume=9,
    openinterest=-1
)

cerebro.adddata(data)

cerebro.run()
cerebro.plot(iplot=False)

依然是基于上面的例子,我们添加了原本没有被导入的每日价格涨跌数据,另外添加了显示新数据的代码,输出应该是这样的

通过比较可以看到新的数据显示在了最下面。