Как найти корень динамической функции, основанной на столбцах набора данных, используя Python - PullRequest
1 голос
/ 12 ноября 2019

Я новичок в Python, и мне нужно перевести некоторый код в R на Python.

Мне нужно найти по одному корню на строку в наборе данных на основе динамической функции, код в R:

library(rootSolve
library(dplyr)
library(plyr)

 dataset = data.frame(A = c(10,20,30),B=c(20,10,40), FX = c("A+B-x","A-B+x","A*B-x"))

 sol<- adply(dataset,1, summarize,
               solution_0= uniroot.all(function(x)(eval(parse(text=as.character(FX),dataset))),lower = -10000, upper = 10000, tol = 0.00001))

Этот код возвращает [30, -10,1200] какрешение для каждой строки.

В Python я прочитал документацию по оптимизации пакета sciPy, но я не нашел подходящий для меня код:

Я попробовал подобные решения ниже,но без успеха:

import pandas as pd
from scipy.optimize import fsolve as fs

data = {'A': [10,20,30],
        'B': [20,10,40],
        'FX': ["A+B-x","A-B+x","A*B-x"]}
df = pd.DataFrame(data)

def func(FX):
    return(exec(FX))

fs(func(df.FX),x0=0,args=df) 

У кого-то есть идеи, как решить эту проблему?

Очень спасибо.

1 Ответ

0 голосов
/ 12 ноября 2019

SymPy - это символическая математическая библиотека для Python. Ваш вопрос может быть решен как:

import pandas as pd
from sympy import Symbol, solve
from sympy.parsing.sympy_parser import parse_expr

data = {'A': [10,20,30],
        'B': [20,10,40],
        'FX': ["A+B-x","A-B+x","A*B-x"]}

df = pd.DataFrame(data)

x = Symbol("x", real=True)

for index, row in df.iterrows():
    F = parse_expr(row['FX'], local_dict={'A': row['A'], 'B': row['B'], 'x':x})
    print (row['A'], row['B'], row['FX'], "-->", F, "-->", solve(F, x))

Это выводит:

10 20 A+B-x --> 30 - x --> [30]
20 10 A-B+x --> x + 10 --> [-10]
30 40 A*B-x --> 1200 - x --> [1200]

Обратите внимание, что решение SymPy возвращает список решений. Если вы уверены, что всегда есть только одно решение, просто используйте solve(F, x)[0]. (Помните, что в отличие от R, Python всегда начинает индексировать с 0.)

С пониманием списка вы можете написать решение в виде:

sol = [ solve(parse_expr(row['FX'], local_dict={'A': row['A'], 'B': row['B'], 'x':x}),
              x)[0] for _, row in df.iterrows() ]

Если у вас много столбцов, вы также можете создатьсловарь с циклом: dict({c:row[c] for c in df.columns}, **{'x':x}) ). Странный синтаксис ** необходим, если вы хотите объединить словари в понимании списка. См. этот пост об объединении словарей.

cols = df.columns # change this if you won't need all columns
sol = [ solve(parse_expr(row['FX'],
                         local_dict=dict({c:row[c] for c in cols}, **{'x':x}) ),
              x)[0].evalf() for _, row in df.iterrows() ]

PS: SymPy обычно сохраняет решения в символической форме, поскольку предпочитает точные выражения. Когда есть, например, дроби или квадратные корни, они не оцениваются сразу. Чтобы получить оцененную форму, используйте evalf(), как в solve(F, x)[0].evalf().

...