几年前尝试过用julia调用python代码(函数),虽然都用PyCall,看起来很方便,但是系统性的总结却不多。
本文主要参考资料:
https://github.com/JuliaPy/PyCall.jl
1、julia调用python现成库中函数
# 调用python中现有的库
using PyCall
math = pyimport("math")
v = math.sin(math.pi / 4) # returns ≈ 1/√2 = 0.70710678...
println("v:",v)
using PyCall
@pyimport numpy as np
@pyimport matplotlib.pyplot as plt
x=np.linspace(0,2pi,1000)
y=np.sin(3x+4*np.cos(2x))
plt.plot(x,y)
plt.show()
2、直接在Julia中写python代码
下面代码在:julia_call_py.jl中
module MyModule
using PyCall
function __init__()
py"""
import numpy as np
def one(x):
return np.sin(x) ** 2 + np.cos(x) ** 2
def hello_world(s):
return s +" hello world!"
"""
end
two(x) = py"one"(x) + py"one"(x)
helloworld(s) = py"hello_world"(s)
end
调用法:
julia> include("julia_call_py.jl")
Main.MyModule
julia> MyModule.two(2)
2.0
julia> MyModule.helloworld("julia")
"julia hello world!"
即可以直接julia中运行。
3、julia调用现成手写的python代码
此时的情况不一样,需要进行特别处理。第一,需要把python代码文件加载进python的工作目录中。
本质上是,sys.path.append(“路径名…”).
在我这里,python代码文件路径是“D:\py_joinquant\julia.py”,和julia代码并不在一个工程目录内。
需要用到pushfirst!函数。
那么路径目录是“D:\py_joinquant\”。
julia> pushfirst!(PyVector(pyimport("sys")."path"), "D:\\py_joinquant\\")
PyObject ['D:\\py_joinquant\\', '', '', 'C:\\Users\\songroom\\.julia\\conda\\3\\python37.zip', 'C:\\Users\\songroom\\.julia\\conda\\3\\DLLs', 'C:\\Users\\songroom\\.julia\\conda\\3\\lib', 'C:\\Users\\songroom\\AppData\\Local\\Programs\\Julia-1.6.0\\bin', 'C:\\Users\\songroom\\.julia\\conda\\3', 'C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages', 'C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages\\win32', 'C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages\\win32\\lib', 'C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages\\Pythonwin']
这样,python就可以找到相应的路径了。这时,你可以看到,sys.path:
julia> pyimport("sys").path
13-element Vector{String}:
"D:\\py_joinquant\\"
""
""
"C:\\Users\\songroom\\.julia\\conda\\3\\python37.zip"
"C:\\Users\\songroom\\.julia\\conda\\3\\DLLs"
"C:\\Users\\songroom\\.julia\\conda\\3\\lib"
"C:\\Users\\songroom\\AppData\\Local\\Programs\\Julia-1.6.0\\bin"
"C:\\Users\\songroom\\.julia\\conda\\3"
"C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages"
"C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages\\win32"
"C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages\\win32\\lib"
"C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages\\Pythonwin"
另外,julia.py文件如下:
import logging as log
def get_corecode_from_code(code):
# IC1906.CCFX=>IC
# IC1906=>IC
# 600036=>600036
# 600036.XSHE =>600036
length = len(code)
if length <2:
log.info("get_corecode_from_code=> code %s may be wrong!",code)
return ""
code_first = code.split('.')
s = code_first[0]
if len(s)==1:
return s.upper()
if s[0].isalpha(): #futures
if s[1].isdigit():
return s[0].upper()
else:
return s[:2].upper()
else:
return s.upper()
引进julia.py文件,并进行调用:
julia> @pyimport julia
julia> julia.get_corecode_from_code("600036")
"600036"
julia> julia.get_corecode_from_code("IC1906.CCFX")
"IC"
julia> pyimport("sys").path
13-element Vector{String}:
"D:\\py_joinquant\\tools.py"
"D:\\py_joinquant\\"
""
""
"C:\\Users\\songroom\\.julia\\conda\\3\\python37.zip"
"C:\\Users\\songroom\\.julia\\conda\\3\\DLLs"
"C:\\Users\\songroom\\.julia\\conda\\3\\lib"
"C:\\Users\\songroom\\AppData\\Local\\Programs\\Julia-1.6.0\\bin"
"C:\\Users\\songroom\\.julia\\conda\\3"
"C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages"
"C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages\\win32"
"C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages\\win32\\lib"
"C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages\\Pythonwin"
julia> julia.get_corecode_from_code("60")
"60"
综合起来,其实还是比较简单的:
pushfirst!(PyVector(pyimport("sys")."path"), "D:\\py_joinquant\\")
@pyimport julia
julia.get_corecode_from_code("600036")
例二:julia调用sklearn中机器学习相关库
有一个sklearn_test.py,路径如下:
C:\Users\songroom\Desktop\sklearn_test.py
from sklearn import datasets
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
def LR_predict():
#使用以后的数据集进行线性回归
loaded_data=datasets.load_boston()
data_X=loaded_data.data
data_y=loaded_data.target
model=LinearRegression()
model.fit(data_X,data_y)
print(model.predict(data_X[:4,:]))
print(data_y[:4])
#参数
print(model.coef_) #如果y=0.1x+0.3 则此行输出的结果为0.1
print(model.intercept_) #此行输出的结果为0.3
print(model.get_params()) #模型定义时定义的参数,如果没有定义则返回默认值
print(model.score(data_X,data_y)) #给训练模型打分,注意用在LinearR中使用R^2 conefficient of determination打分
return model.coef_
julia调用LR_predict()函数:此时会报这个错误!
julia> @pyimport sklearn_test
ERROR: PyError (PyImport_ImportModule
The Python package sklearn_test could not be imported by pyimport. Usually this means
that you did not install sklearn_test in the Python version being used by PyCall.
PyCall is currently configured to use the Julia-specific Python distribution
installed by the Conda.jl package. To install the sklearn_test module, you can
use `pyimport_conda("sklearn_test", PKG)`, where PKG is the Anaconda
package the contains the module sklearn_test, or alternatively you can use the
Conda package directly (via `using Conda` followed by `Conda.add` etcetera).
Alternatively, if you want to use a different Python distribution on your
system, such as a system-wide Python (as opposed to the Julia-specific Python),
you can re-configure PyCall with that Python. As explained in the PyCall
documentation, set ENV["PYTHON"] to the path/name of the python executable
you want to use, run Pkg.build("PyCall"), and re-launch Julia.
) <class 'ModuleNotFoundError'>
ModuleNotFoundError("No module named 'sklearn'")
File "C:\Users\songroom\Desktop\sklearn_test.py", line 1, in <module>
from sklearn import datasets
Stacktrace:
[1] pyimport(name::String)
@ PyCall ~\.julia\packages\PyCall\BD546\src\PyCall.jl:550
[2] top-level scope
@ ~\.julia\packages\PyCall\BD546\src\PyCall.jl:594
此时,需要通过Conda.add()是可以解决的。
另外,需要注意的是,sklearn库在add时名称是全称。
julia> using Conda
julia> Conda.add("scikit-learn")
julia> pyimport("sklearn")
PyObject <module 'sklearn' from 'C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages\\sklearn\\__init__.py'>
其它操作如下:
julia> using PyCall
julia> pushfirst!(PyVector(pyimport("sys")."path"), "C:\\Users\\songroom\\Desktop\\")
PyObject ['C:\\Users\\songroom\\Desktop\\', 'C:\\Users\\songroom\\.julia\\conda\\3\\python37.zip', 'C:\\Users\\songroom\\.julia\\conda\\3\\DLLs', 'C:\\Users\\songroom\\.julia\\conda\\3\\lib', 'C:\\Users\\songroom\\AppData\\Local\\Programs\\Julia-1.6.0\\bin', 'C:\\Users\\songroom\\.julia\\conda\\3', 'C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages', 'C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages\\win32', 'C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages\\win32\\lib', 'C:\\Users\\songroom\\.julia\\conda\\3\\lib\\site-packages\\Pythonwin']
julia> @pyimport sklearn_test
julia> sklearn_test.LR_predict()
[30.00384338 25.02556238 30.56759672 28.60703649]
[24. 21.6 34.7 33.4]
[-1.08011358e-01 4.64204584e-02 2.05586264e-02 2.68673382e+00
-1.77666112e+01 3.80986521e+00 6.92224640e-04 -1.47556685e+00
3.06049479e-01 -1.23345939e-02 -9.52747232e-01 9.31168327e-03
-5.24758378e-01]
36.459488385089855
{'copy_X': True, 'fit_intercept': True, 'n_jobs': None, 'normalize': False, 'positive': False}
0.7406426641094095
13-element Vector{Float64}:
-0.10801135783679539
0.04642045836687953
0.020558626367068917
2.6867338193448442
-17.766611228299986
3.8098652068092282
0.0006922246403431768
-1.47556684560025
0.30604947898516427
-0.012334593916574021
-0.9527472317072921
0.00931168327379375
-0.5247583778554881
julia>
可以看到,julia调用python的sklearn库代码成功!
需要注意的是,在pyimport(“sklearn_test”)仍然成功的情况下,如果还说发现找不到相关的sklearn库,或sklearn_test文件,可能需要退出julia repl,重启,对操作进行初始化一下。
整体代码如下:
using PyCall
pushfirst!(PyVector(pyimport("sys")."path"), "C:\\Users\\songroom\\Desktop\\")
@pyimport sklearn_test
sklearn_test.LR_predict()
4、调用类中的方法
还是这个sklearn_test.py文件,目录不变:
C:\Users\songroom\Desktop\sklearn_test.py
此时,我们把原来的python中函数形式改成类中方法形式,如下:
from sklearn import datasets
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
import numpy.polynomial
class MyNet(numpy.polynomial.Polynomial):
def __init__(self, x=10):
self.x = x
def my_method(self, arg1):
return arg1 + 20
@property
def x2(self):
return self.x * 2
@x2.setter
def x2(self, new_val):
self.x = new_val / 2
def add(self,a,b):
return a+b
def LR_predict(self):
#使用以后的数据集进行线性回归
loaded_data=datasets.load_boston()
data_X=loaded_data.data
data_y=loaded_data.target
model=LinearRegression()
model.fit(data_X,data_y)
print(model.predict(data_X[:4,:]))
print(data_y[:4])
#参数
print(model.coef_) #如果y=0.1x+0.3 则此行输出的结果为0.1
print(model.intercept_) #此行输出的结果为0.3
print(model.get_params()) #模型定义时定义的参数,如果没有定义则返回默认值
print(model.score(data_X,data_y)) #给训练模型打分,注意用在LinearR中使用R^2 conefficient of determination打分
return model.coef_
此时如何从julia中调用python中的MyNet.LR_predict()?完整的脚本代码如下:
using PyCall
pushfirst!(PyVector(pyimport("sys")."path"), "C:\\Users\\songroom\\Desktop\\")
@pyimport sklearn_test
my_net = sklearn_test.MyNet()
my_net.LR_predict()
5、julia与python类的深度融合 : @pydef
借用PyCall.jl中的例子
using PyCall
P = pyimport("numpy.polynomial")
@pydef mutable struct Doubler <: P.Polynomial
function __init__(self, x=10)
self.x = x
end
my_method(self, arg1::Number) = arg1 + 20
x2.get(self) = self.x * 2
function x2.set!(self, new_val)
self.x = new_val / 2
end
end
value = Doubler().x2;
println("value :",value)
执行:
julia> @time include("julia_call_py.jl")
value :20
0.276265 seconds (574.10 k allocations: 35.587 MiB, 3.07% gc time, 94.97% compilation time)
以上就是julia调用python中原生函数,类中方法的几种方式。