Вызов Python от Джулии

#julia #pycall

#джулия #pycall

Вопрос:

Я новичок в Julia, и у меня есть функция Python, которую я хочу использовать в Julia. В основном, что делает функция, это принимает фрейм данных (передается как numpy ndarray), значение фильтра и список индексов столбцов (из массива) и запускает логистическую регрессию с использованием statsmodels пакета на Python. До сих пор я пробовал это:

 using PyCall

py"""
import pandas as pd
import numpy as np
import random
import statsmodels.api as sm
import itertools
def reg_frac(state, ind_vars):
    rows = 2000
    total_rows = rows*13
    data = pd.DataFrame({
    'state': ['a', 'b', 'c','d','e','f','g','h','i','j','k','l','m']*rows, 
    'y_var': [random.uniform(0,1) for i in range(total_rows)], 
    'school': [random.uniform(0,10) for i in range(total_rows)], 
    'church': [random.uniform(11,20) for i in range(total_rows)]}).to_numpy()
    try:
        X, y = sm.add_constant(np.array(data[(data[:,0] == state)][:,ind_vars], dtype=float)), np.array(data[(data[:,0] == state), 1], dtype=float)
        model = sm.Logit(y, X).fit(cov_type='HC0', disp=False)      
        rmse = np.sqrt(np.square(np.subtract(y, model.predict(X))).mean())
    except:
        rmse = np.nan
    return [state, ind_vars, rmse] 
"""

reg_frac(state, ind_vars) = (py"reg_frac"(state::Char, ind_vars::Array{Any}))
  

Однако, когда я запускаю это, я не ожидаю, что результаты будут NaN . Я думаю, что это работает, но я чего-то не хватает.

 reg_frac('b', Any[i for i in 2:3])

  0.000244 seconds (249 allocations: 7.953 KiB)
3-element Array{Any,1}:
    'b'
    [2, 3]
 NaN
  

Любая помощь приветствуется.

Комментарии:

1. Работает ли код на Python (без вызова его из Julia)? Вы добавили except предложение, которое устанавливает rmse значение np.nan , поэтому не было бы слишком удивительно, если бы оно в конечном итоге было NaN. Также есть какая-нибудь причина, по которой вы просто не вписываетесь в модель logit в Julia?

2. Да, код работает на python. модель — это просто пример. У меня есть модель в Julia. Я просто хочу иметь возможность импортировать функции python как часть моего путешествия по Джулии.

3. @PrzemyslawSzufel Это работает на Python. Я просто запускаю его, и он работает. Вы уверены, что хорошо его запускаете? Просто запустите reg_frac('b',[2,3]) . Это был мой ответ ['b', [2, 3], 0.28999238875117006]

4. Это не работает. И это не может работать, потому что в вашем коде есть несколько неопределенных переменных, таких как rows или total_rows .

5. @PrzemyslawSzufel вы правы. Виноват, у меня эти переменные уже были загружены. Я обновил этот пост

Ответ №1:

В коде Python у вас есть str s, в то время как в коде Julia у вас есть Char s — это не одно и то же.

Python:

 >>> type('a')
<class 'str'>
  

Джулия:

 julia> typeof('a')
Char
  

Следовательно, ваши сравнения не работают.
Ваша функция может выглядеть следующим образом:

 reg_frac(state, ind_vars) = (py"reg_frac"(state::String, ind_vars::Array{Any}))
  

И теперь:

 julia> reg_frac("b", Any[i for i in 2:3])
3-element Array{Any,1}:
  "b"
  [2, 3]
 0.2853707270515166
  

Тем не менее, я рекомендовал использовать Vector{Float64} то, что в PyCall преобразуется в полете в вектор numpy, а не использовать Vector{Any} , так что, похоже, ваш код все еще можно улучшить (в зависимости от того, что вы на самом деле планируете делать).

Комментарии:

1. О, вау, ты сделал мой день! На самом деле я собираюсь повторить это для миллионов комбинаций state и ind_vars , поэтому любые улучшения производительности будут очень полезны. Меня интересует, где использовать Vector{Float64} . Опять же, как мне лучше всего реструктурировать свой код для повышения производительности / скорости

2. Вы имеете в виду reg_frac(state, ind_vars) = (py"reg_frac"(state::String, ind_vars::Vector{Float64})) ?

3. да, что-то вроде этого. Вы также могли бы написать reg_frac(state::String, ind_vars::Vector{Float64}) = (py"reg_frac"(state, ind_vars)) , что обычно и делается.