如何在Julia中使用PyCall将Python输出转换为Julia DataFrame

Con*_*tin 5 python dataframe julia quandl

我想从quandlJulia中检索一些数据并对其进行分析.遗憾的是,还没有正式的API(尚未).我知道这个解决方案,但它的功能仍然非常有限,并且不遵循与原始Python API相同的语法.

我认为使用PyCallJulia中的官方Python API来检索数据是明智之举.这确实产生了输出,但我不知道如何将其转换为我能够在Julia中使用的格式(理想情况下是a DataFrame).

我尝试了以下内容.

using PyCall, DataFrames
@pyimport quandl

data = quandl.get("WIKI/AAPL", returns = "pandas");
Run Code Online (Sandbox Code Playgroud)

Julia将此输出转换为a Dict{Any,Any}.当使用returns = "numpy"而不是returns = "pandas",我最终得到一个PyObject rec.array.

我怎样才能data成为朱莉娅DataFrame因为quandl.jl要退呢?请注意,这quandl.jl不是我的选择,因为它不支持自动检索多个资产,并且缺少其他一些功能,因此我必须使用Python API.

谢谢你的任何建议!

nic*_*y12 5

这是一个选项:

首先,从您的data对象中提取列名:

julia> colnames = map(Symbol, data[:columns]);
12-element Array{Symbol,1}:
 :Open                
 :High                
 :Low                 
 :Close               
 :Volume              
 Symbol("Ex-Dividend")
 Symbol("Split Ratio")
 Symbol("Adj. Open")  
 Symbol("Adj. High")  
 Symbol("Adj. Low")   
 Symbol("Adj. Close") 
 Symbol("Adj. Volume")
Run Code Online (Sandbox Code Playgroud)

然后将所有列倒入DataFrame:

julia> y = DataFrame(Any[Array(data[c]) for c in colnames], colnames)

6×12 DataFrames.DataFrame
? Row ? Open  ? High  ? Low   ? Close ? Volume   ? Ex-Dividend ? Split Ratio ?
??????????????????????????????????????????????????????????????????????????????
? 1   ? 28.75 ? 28.87 ? 28.75 ? 28.75 ? 2.0939e6 ? 0.0         ? 1.0         ?
? 2   ? 27.38 ? 27.38 ? 27.25 ? 27.25 ? 785200.0 ? 0.0         ? 1.0         ?
? 3   ? 25.37 ? 25.37 ? 25.25 ? 25.25 ? 472000.0 ? 0.0         ? 1.0         ?
? 4   ? 25.87 ? 26.0  ? 25.87 ? 25.87 ? 385900.0 ? 0.0         ? 1.0         ?
? 5   ? 26.63 ? 26.75 ? 26.63 ? 26.63 ? 327900.0 ? 0.0         ? 1.0         ?
? 6   ? 28.25 ? 28.38 ? 28.25 ? 28.25 ? 217100.0 ? 0.0         ? 1.0         ?

? Row ? Adj. Open ? Adj. High ? Adj. Low ? Adj. Close ? Adj. Volume ?
?????????????????????????????????????????????????????????????????????
? 1   ? 0.428364  ? 0.430152  ? 0.428364 ? 0.428364   ? 1.17258e8   ?
? 2   ? 0.407952  ? 0.407952  ? 0.406015 ? 0.406015   ? 4.39712e7   ?
? 3   ? 0.378004  ? 0.378004  ? 0.376216 ? 0.376216   ? 2.6432e7    ?
? 4   ? 0.385453  ? 0.38739   ? 0.385453 ? 0.385453   ? 2.16104e7   ?
? 5   ? 0.396777  ? 0.398565  ? 0.396777 ? 0.396777   ? 1.83624e7   ?
? 6   ? 0.420914  ? 0.422851  ? 0.420914 ? 0.420914   ? 1.21576e7   ?
Run Code Online (Sandbox Code Playgroud)

感谢@Matt B.提出的简化代码的建议.

上面的问题是列类型Any在数据框内.为了使它更有效,这里有一些功能可以完成工作:

# first, guess the Julia equivalent of type of the object
function guess_type(x::PyCall.PyObject)
  string_dtype = x[:dtype][:name]
  julia_string = string(uppercase(string_dtype[1]), string_dtype[2:end])

  return eval(parse("$julia_string"))
end

# convert an individual column, falling back to Any array if the guess was wrong
function convert_column(x)
  y = try Array{guess_type(x)}(x) catch Array(x) end
  return y
end

# put everything together into a single function
function convert_pandas(df)
  colnames =  map(Symbol, data[:columns])
  y = DataFrame(Any[convert_column(df[c]) for c in colnames], colnames)

  return y
end
Run Code Online (Sandbox Code Playgroud)

上面的内容,当应用于您时,data会提供与以前相同的列名,但具有正确的Float64列类型:

y = convert_pandas(data);
showcols(y)
9147×12 DataFrames.DataFrame
? Col # ? Name        ? Eltype  ? Missing ?
???????????????????????????????????????????
? 1     ? Open        ? Float64 ? 0       ?
? 2     ? High        ? Float64 ? 0       ?
? 3     ? Low         ? Float64 ? 0       ?
? 4     ? Close       ? Float64 ? 0       ?
? 5     ? Volume      ? Float64 ? 0       ?
? 6     ? Ex-Dividend ? Float64 ? 0       ?
? 7     ? Split Ratio ? Float64 ? 0       ?
? 8     ? Adj. Open   ? Float64 ? 0       ?
? 9     ? Adj. High   ? Float64 ? 0       ?
? 10    ? Adj. Low    ? Float64 ? 0       ?
? 11    ? Adj. Close  ? Float64 ? 0       ?
? 12    ? Adj. Volume ? Float64 ? 0       ?
Run Code Online (Sandbox Code Playgroud)


Mat*_* B. 4

您遇到了 Python/Pandas 版本的差异。我碰巧有两种可以轻松使用的配置;Python 2 中的 Pandas 0.18.0 和 Python 3 中的 Pandas 0.19.1。 @niczky12提供的答案在第一个配置中运行良好,但我Dict{Any,Any}在第二个配置中看到了你的行为。基本上,这两种配置之间发生了一些变化,例如 PyCall 检测 Pandas 对象的类似映射的接口,然后通过自动转换将该接口公开为字典。这里有两个选项:

  1. 使用字典界面:

    data = quandl.get("WIKI/AAPL", returns = "pandas")
    cols = keys(data)
    df = DataFrame(Any[collect(values(data[c])) for c in cols], map(Symbol, cols))
    
    Run Code Online (Sandbox Code Playgroud)
  2. 显式禁用自动转换并使用 PyCall 接口提取列,如niczky12 在另一个答案中演示的那样。请注意,这data[:Open]将自动转换为映射字典,并且data["Open"]仅返回PyObject.

    data = pycall(quandl.get, PyObject, "WIKI/AAPL", returns = "pandas")
    cols = data[:columns]
    df = DataFrame(Any[Array(data[c]) for c in cols], map(Symbol, cols))
    
    Run Code Online (Sandbox Code Playgroud)

但在这两种情况下,请注意,最重要的日期索引不包含在结果数据框中。您几乎肯定想将其添加为一列:

df[:Date] = collect(data[:index])
Run Code Online (Sandbox Code Playgroud)