Как использовать PyCall в Юля для преобразования выходного Python для Юли таблицы данных
Я хотел бы получить некоторые данные из quandl
и проанализировать их в Julia. К сожалению, официального API для этого пока нет. Я знаю это решение, но оно все еще довольно ограничено в функциональности и не следует тому же синтаксису, что и исходный API Python.
Я думал, что это будет умная вещь, чтобы использовать PyCall
, чтобы получить данные, используя официальный API-интерфейс Python изнутри Джулии. Это действительно дает результат, но я не уверен, как я могу преобразовать его в формат, который я мог бы использовать внутри Julia (в идеале a DataFrame
).
using PyCall, DataFrames
@pyimport quandl
data = quandl.get("WIKI/AAPL", returns = "pandas");
Джулия преобразует этот вывод в Dict{Any,Any}
. При использовании returns = "numpy"
вместо returns = "pandas"
я получаю PyObject rec.array
.
Как я могу заставить data
быть Джулией DataFrame
, поскольку quandl.jl
вернет ее? Обратите внимание, что quandl.jl
не подходит для меня, потому что он не поддерживает автоматическое извлечение нескольких ресурсов и не имеет нескольких других функций, поэтому важно, чтобы я мог использовать Python ПРИКЛАДНОЙ ПРОГРАММНЫЙ ИНТЕРФЕЙС.
Спасибо за любые предложения!
3 ответа:
Вы столкнулись с различием в версиях Python/Pandas. У меня есть две конфигурации, которые легко доступны для меня: панды 0.18.0 в Python 2 и панды 0.19.1 в Python 3. Ответ @niczky12 при условии хорошо работает в первой конфигурации, но я вижу ваше
Dict{Any,Any}
поведение во второй конфигурации. В принципе, что-то меняется между этими двумя конфигурациями, так что PyCall обнаруживает подобный отображению интерфейс для объектов Pandas, а затем предоставляет этот интерфейс в качестве словарь через автоматическое преобразование. Здесь есть два варианта:
Работа с интерфейсом словаря:
data = quandl.get("WIKI/AAPL", returns = "pandas") cols = keys(data) df = DataFrame(Any[collect(values(data[c])) for c in cols], map(Symbol, cols))
Явно отключите автоматическое преобразование и используйте интерфейс 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))
В обоих случаях, однако, обратите внимание, что все-важные индекс даты не включается в результирующий фрейм данных. Вы почти наверняка хотите добавить это в виде столбца:
df[:Date] = collect(data[:index])
Вот один из вариантов:
Сначала извлеките имена столбцов из объекта
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")
Затем вылейте все свои столбцы в фрейм данных:
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 │
Спасибо @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
Выше, когда применяется к вашему
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 │
Существует API. Просто используй Квандл.дл: https://github.com/milktrader/Quandl.jl
using Quandl data = quandlget("WIKI/AAPL")
Это имеет дополнительное преимущество в получении данных в удобном формате Julia (TimeArray), который имеет соответствующие методы, определенные для работы с такими данными.