Py

利用python C-API协议,实现在 DolphinDB 内调用 python 环境中的第三方库。本插件使用了pybind11 库。

准备工作

依赖库

  • libpython3.6m.so

    如果版本不同,在使用 CMake 构建插件时可用 DPYTHON:STRING 指定对应版本。目前只支持 Python3.6 版本。

  • libDolphinDB.so(release130分支动态链接openblas.so动态库版本)

    请参考插件开发教程进行配置。

  • libOpenblas.so

    如果无法找到,需要自行安装 OpenBLAS。Linux 中可直接用以下命令安装:

    git clone https://github.com/xianyi/OpenBLAS.git
    make
    make install PREFIX=your_installation_directory

    默认安装目录为 /opt/OpenBLAS,请将该路径添加到环境变量中。

注意:开发过程中需要有完整的 Python 运行环境,且插件运行时 sys.path 打印的路径要和安装的运行环境一致。

安装插件

版本要求

  • DolphinDB Server: 2.00.10 及更高版本。
  • x86-64 的 Linux JIT 版本。
  • 仅支持 Python3.6 环境。

安装步骤

  1. 在DolphinDB 客户端中使用 listRemotePlugins 命令查看插件仓库中的插件信息。

    注意:仅展示当前操作系统和 server 版本支持的插件。若无预期插件,可自行编译(请自行选择对应分支下的插件)或在 DolphinDB 用户社区进行反馈。

    login("admin", "123456")
    listRemotePlugins()
  2. 使用 installPlugin 命令完成插件安装。

    installPlugin("py")
  3. 修改配置参数,添加 globalDynamicLib 参数。如果是单节点模式,需要修改 dolphindb.cfg;如果是集群模式,需要修改 cluster.cfg。

    globalDynamicLib=/path_to_libpython3.6m.so/libpython3.6m.so
  4. 使用 loadPlugin 命令加载插件。

    loadPlugin("py")

接口说明

toPy

语法

py::toPy(obj)

详情

将DolphinDB 数据类型转换为 Python 对象,目前支持的数据类型见 DolphinDB 数据类型转成 Python 对象。

参数

obj 需要转换的 DolphinDB 数据对象。

例子

 x = 1 2 3 4;
 pyArray = py::toPy(x);
 
 y = 2 3 4 5;
 d = dict(x, y);
 pyDict = py::toPy(d);

fromPy

语法

py::fromPy(obj, [addIndex=false])

详情

将 Python 对象转换为 DolphinDB 数据类型,目前支持的数据类型见 Python 对象转成 DolphinDB 对象。pandas.DataFrame 转换成 table 保留 index 的例子见 Dataframe 转换成 table 保留 index。

参数

obj 需要转换的 Python 对象。

addIndex 布尔值,表示是否将 pandas.DataFrame 的 index 作为转换后的 table 的第一列。默认值为 false,表示舍弃 pandas.DataFrame 的 index 列。仅当 obj 为 pandas.DataFrame 时才需设置该参数。

例子

 x = 1 2 3 4;
 l = py::toPy(x);
 re = py::fromPy(l);
 re;

importModule

语法

py::importModule(moduleName)

详情

导入 python 模块(子模块),需要确保环境中已安装对应模块。可用 pip3 list 查看是否安装,若未安装须通过 pip3 install 命令进行安装。

注:如果需要导入自定义的模块,则需要将该模块文件拷贝到 sys.path 打印的 lib 路径下或者 dolphindb 所在的目录下。

参数

moduleName STRING 类型标量,表示需要导入的模块名称。

例子

np = py::importModule("numpy"); //导入 numpy

linear_model = py::importModule("sklearn.linear_model"); //导入 sklearn 子模块 linear_model

cmd

语法

py::cmd(command)

详情

运行 Python 脚本。

参数

command STRING 类型标量,要运行的 Python 脚本。

例子

 sklearn = py::importModule("sklearn"); //导入 sklearn
 py::cmd("from sklearn import linear_model"); //从 sklearn 导入 linear_model 模块

getObj

语法

py::getObj(module, objName)

详情

获取模块(或对象)的子模块(或属性)。获取子模块时要确保子模块已经导入,若没有导入,可用 py::cmd 执行 from ... import ... 语句导入。

参数

module 预先导入的模块,如 py::importModule 的返回值。 objName STRING 类型标量,表示目标对象名称。

例子

np = py::importModule("numpy"); //导入 numpy
random = py::getObj(np, "random"); //获取 numpy 子模块 random

sklearn = py::importModule("sklearn"); //导入 sklearn
py::cmd("from sklearn import linear_model"); //导入sklearn子 模块
linear_model = py::getObj(sklearn, "linear_model");  //获取 sklearn 子模块 linear_model

注:导入 numpy 时会自动导入 random 子模块,所以无需运行 py::cmd("from numpy import random") 便可通过 py::getObject 获取子模块;而导入 sklearn 时不会自动导入子模块,所以需要通过 py::cmd("from sklearn import linear_model") 导入子模块后才能执行 py::getObject 获取子模块。若只使用子模块功能可通过 linear_model=py::importModule("sklearn.linear_model") 获取子模块,这种方式更加方便。

getFunc

语法

py::getFunc(module, funcName, [convert=true])

详情

获取 python 模块内的静态方法。可直接调用返回的函数对象,该函数可直接接受 DolphinDB 的数据类型作为入参,无需预先转换。目前函数不支持关键字参数,若设置 convert=true,则调用结果会直接返回 DolphinDB 的数据类型(在能够转换的情况),若设置 convert=false,则调用结果不会转换为 Python 对象。

参数

module 预先导入的模块,如 py::importModulepy::getObj 的返回值。 funcName STRING 类型标量,需要获取的函数名称。 convert 布尔值,表示在调用该函数后结果是否自动转换成 DolphinDB 对应的数据类型,默认为 true。

例子

np = py::importModule("numpy"); //导入 numpy
eye = py::getFunc(np, "eye"); //获取 numpy 中的 eye 函数

np = py::importModule("numpy"); //导入 numpy
random = py::getObj(np, "random"); //获取 numpy 子模块 random
randint = py::getFunc(random, "randint"); //获取 random 中的 randint 函数

getInstanceFromObj

语法

py::getInstanceFromObj(obj, [args])

详情

通过预先获得的 Python 类对象获取 Python 类实例对象。返回的对象支持以 " . " 方式访问类属性与类方法。在能够进行数据类型转换时返回 DolphinDB 数据类型,否则返回 Python 对象。

参数

obj 预先获得的 Python 类对象,如 py::getObj 的返回值。 args 要传给实例对象的参数,若没有则不填。

例子

 sklearn = py::importModule("sklearn");
 py::cmd("from sklearn import linear_model");
 linearR = py::getObj(sklearn,"linear_model.LinearRegression")
 linearInst = py::getInstanceFromObj(linearR);

getInstance

语法

py::getInstance(module, objName, [args])

详情

直接从模块中获取 Python 类实例对象。返回的对象支持以 " . " 方式访问类属性与类方法。在能够进行数据类型转换时返回 DolphinDB 数据类型,否则返回 Python 对象。

注意:py::getFunc 获取的是模块中的静态方法。如果要调用实例方法,需要用 py::getInstanceFromObjpy::getInstance 获取类实例对象,然后通过 " . " 的方式访问类方法。

参数

module 预先导入的模块,如 py::importModule 的返回值。 objName STRING 类型标量,目标对象名称。 args 要传给实例对象的参数,若没有则不填。

例子

linear_model = py::importModule("sklearn.linear_model"); //导入 sklearn 子模块 linear_model
linearInst = py::getInstance(linear_model,"LinearRegression") 

reloadModule

py::reloadModule(module)

详情

如果修改了之前导入的模块,重新执行 importModule 并不能导入修改后的模块,需要调用 reloadModule 重新导入该模块才能获取到修改后的模块。

参数

module 预先导入的模块,如 py::importModule 的返回值。

例子

model = py::importModule("fibo"); //fibo 为上文中自定义的模块

model = py::reloadModule(model);  //如果修改了 fibo.py,则需要调用 reloadModule 重新导入该模块才能获取到修改后的模块

实例

加载插件并初始化

loadPlugin("/path/to/plugin/PluginPy.txt");
use py;

数据结构互转

x = 1 2 3 4;
y = 2 3 4 5;
d = dict(x, y);
pyDict = py::toPy(d);
Dict = py::fromPy(pyDict);
Dict;

调用系统库打印 python 默认路径

sys = py::importModule("sys");
path = py::getObj(sys, "path");
dpath = py::fromPy(path);
dpath;

导入 numpy 并执行静态方法

np = py::importModule("numpy"); //导入 numpy
eye = py::getFunc(np, "eye"); //获取 numpy 中的 eye 函数
re = eye(3); //执行 eye 函数生成对角矩阵
re;

random = py::getObj(np, "random"); //获取 numpy 子模块 random
randint = py::getFunc(random, "randint"); //获取 random 中的 randint 函数
re = randint(0,1000,[2,3]); //执行 randint 函数
re;

导入 sklearn 并执行实例方法

//方法一
linear_model = py::importModule("sklearn.linear_model"); //导入 sklearn 子模块 linear_model
linearInst = py::getInstance(linear_model,"LinearRegression") 
//方法二
sklearn = py::importModule("sklearn"); //导入 sklearn
py::cmd("from sklearn import linear_model"); //从 sklearn 导入 linear_model 模块
linearR = py::getObj(sklearn,"linear_model.LinearRegression")
linearInst = py::getInstanceFromObj(linearR);

X = [[0,0],[1,1],[2,2]];
Y = [0,1,2];
linearInst.fit(X, Y); //调用 fit 函数
linearInst.coef_; // output: [0.5,0.5]
linearInst.intercept_; // output: 1.110223E-16 ~ 0
Test = [[3,4],[5,6],[7,8]];
re = linearInst.predict(Test); //调用 predict 函数
re; //output: [3.5, 5.5, 7.5]

datasets = py::importModule("sklearn.datasets");
load_iris = py::getFunc(datasets, "load_iris"); //获取静态函数 load_iris
iris = load_iris(); //调用静态函数 load_iris

datasets = py::importModule("sklearn.datasets");
decomposition = py::importModule("sklearn.decomposition");
PCA = py::getInstance(decomposition, "PCA");
py_pca=PCA.fit_transform(iris['data'].row(0:3)); //取 iris['data'] 前三行数据进行训练
py_pca.row(0);  //output:[0.334781147691283, -0.011991887788418, 2.926917846106032e-17]

注意:DolphinDB 中若要从矩阵中取行数据要用 row 函数,如上例中的 iris['data'].row(0:3) 为取前三行数据。iris['data'][0:3] 为取前三列数据。

导入自定义模块并调用其中的静态方法

本例中我们自己实现了一个如下所示的 python 模块,里面有两个静态方法,fib(n) 打印从 0 到 n 的 Fibonacci 数列,fib2(n) 返回从 0 到 n 的 Fibonacci 数列。我们将该模块保存为 fibo.py,并将其拷贝到 dolphindb 所在的目录下(或者拷贝到 sys.path 打印的 lib 路径下):

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()

def fib2(n):   # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result

之后我们便能加载插件,在 dolphindb 中导入该模块进行使用:

loadPlugin("/path/to/plugin/PluginPy.txt"); //加载插件

fibo = py::importModule("fibo");  //导入该模块
fib = py::getFunc(fibo,"fib");  //获取模块中的 fib 函数
fib(10);  //调用 fib 函数,打印出 0 1 1 2 3 5 8
fib2 = py::getFunc(fibo,"fib2"); //获取模块中的 fib2 函数
re = fib2(10);  //调用 fib2 函数
re;   //output: 0 1 1 2 3 5 8

DataFrame 转换成 table 并保留index

在调用某些 Python 函数时,如果返回 DataFrame,若要保留 index 作为转换后 table 的第一列,需要在调用 getFunc 时指定 convert=false,然后调用 fromPy 函数且设置 addIndex=true,将结果转换成 table。

首先实现一个函数返回一个 pandas.DataFrame,将其保存成 demo.py;然后将其拷贝到 dolphindb 所在的目录下(或者拷贝到 sys.path 打印的 lib 路径下):

import pandas as pd
import numpy as np
def createDF():
    index=pd.Index(['a','b','c'])
    df=pd.DataFrame(np.random.randint(1,10,(3,3)),index=index)
    return df

之后加载插件,导入模块加载函数并调用,这样返回结果中的第一列便为 dataframe 的 index:

loadPlugin("/path/to/plugin/PluginPy.txt"); //加载插件

model = py::importModule("demo");
func1 = py::getFunc(model, "createDF", false)
tem = func1()
re =  py::fromPy(tem, true)

支持的数据类型

DolphinDB 数据类型转成 Python 对象

DolphinDB 数据类型Python 数据类型
BOOLbool
CHARint64
SHORTint64
INTint64
LONGint64
DOUBLEfloat64
FLOATfloat64
STRINGString
DATEdatetime64[D]
MONTHdatetime64[M]
TIMEdatetime64[ms]
MINUTEdatetime64[m]
SECONDdatetime64[s]
DATETIMEdatetime64[s]
TIMESTAMPdatetime64[ms]
NANOTIMEdatetime64[ns]
NANOTIMESTAMPdatetime64[ns]
DATEHOURdatetime64[s]
vectorNumPy.array
matrixNumPy.array
setSet
dictionaryDictionary
tablepandas.DataFrame
  • DolphinDB CHAR 类型会被转换成 Python int64 类型。
  • 向量和矩阵都会转成 numpy.array,时间类型都会转成 Python pandas 中的时间类型,所以 Python 环境中需要安装 numpy 和 pandas 模块。
  • 由于 Python pandas 中所有有关时间的数据类型均为 datetime64[ns],DolphinDB 中 table 的所有时间类型数据均会被转换为 datetime64[ns] 类型。MONTH 类型,如 2012.06M,会被转换为 2012-06-01(即月份当月的第一天).由于 pandas 时间戳范围限制,MONTH 范围要在 1970.01M-2262.04M 之间,DATE 和 DATETIME 日期范围要在 1677.09.22-2062.04.11 之间。TIME, MINUTE, SECOND 与 NANOTIME 类型不包含日期信息,转换时会自动添加 1970-01-01,例如 13:30m 会被转换为 1970-01-01 13:30:00。
  • DolphinDB 中的逻辑型、数值型和时序类型的 NULL 值默认情况下会转换成 NaN 或 NaT;字符串的 NULL 值为空字符串。如果向量中包含 NULL 值,数据类型可能会发生改变,比如 BOOL 类型的向量中如果包含 NULL 值,NULL 会转换成 NaN,因此数据类型变成 float64;BOOL 类型中的 True 会变成 1,False 会变成 0。

Python 对象转成 DolphinDB 对象

Python 数据类型DolphinDB 数据类型
boolBOOL
int8CHAR
int16SHORT
int32INT
int64LONG
float32FLOAT
float64DOUBLE
StringSTRING
datetime64[M]MONTH
datetime64[D]DATE
datetime64[m]MINUTE
datetime64[s]DATETIME
datetime64[h]DATEHOUR
datetime64[ms]TIMESTAMP
datetime64[us]NANOTIMESTAMP
datetime64[ns]NANOTIMESTAMP
Tuplevector
Listvector
Dictionarydictionary
Setset
NumPy.arrayvector(1维) / matrix(2维)
pandas.DataFrametable
  • numpy.array 会根据维度转换成向量(1维)或者矩阵(2维)。

  • pandas.DataFrame 中的时间数据类型都是 datetime64[ns],所以在转换成 table 时,时间类型都会转换成 NANOTIMESTAMP 类型。

  • 从 pandas.DataFrame 转换成 table 时,如果列名不符合 DolphinDB 要求的列名规范,则会根据以下规则自动调整列名:

    • 若数据中列名存在中文或英文字母、数字或下划线之外的字符,将其转换为下划线。
    • 若数据中列名第一个字符不是中文或英文字母,添加 ”c” 作为该列名首字符。