Comment appeler Python ou Julia à partir de Ruby (implémentation expérimentale)

Je crée un joyau appelé virtual_module qui peut appeler les packages Python et Julia de Ruby. Dans l'exemple ci-dessous, la partie de lecture de la page de manuel de certaines commandes en tant que document est écrite en Ruby, et la partie à traiter par doc2vec est appelée Python et laissée à gensim.

doc2vec.rb


require 'natto'
manpages={}
natto = Natto::MeCab.new
%w"ps ls cat cd top df du touch mkdir".each do |cmd|
  list = []
  natto.parse(`man #{cmd} | col -bx | cat`) do |n|
    list << n.surface
  end
  manpages[cmd] = list
end

require 'virtual_module'
py = VirtualModule.new(:methods=><<EOS, :python=>["gensim"])
class LabeledListSentence(object):
    def __init__(self, words_list, label_list):
        self.words_list = words_list
        self.label_list = label_list

    def __iter__(self):
        for i, words in enumerate(self.words_list):
            yield gensim.models.doc2vec.LabeledSentence(words, [self.label_list[i]])

EOS
model = py.gensim.models.doc2vec.Doc2Vec(py.LabeledListSentence(manpages.values, manpages.keys), min_count:0)
p model.docvecs.most_similar(["ps"]) # [["top", 0.5594387054443359], ["cat", 0.46929454803466797], ["df", 0.3900265693664551], ["mkdir", 0.38811227679252625], ["du", 0.23663029074668884], ["ls", 0.15436093509197235], ["cd", -0.1965409815311432], ["touch", -0.38958919048309326]]

J'ai utilisé ceci pour ajouter une fonction pour extraire des articles liés à l'aide de doc2vec qui fonctionne sur Ruby sur mon blog (créé par Sinatra), mais c'était un peu pratique. Je ne sais pas combien de personnes seront heureuses à part moi, mais (bien que ce soit assez gênant) vous pourrez également utiliser scikit-learn. Aller.

En plus de doc2vec, des exemples d'utilisation de scicit-learn sont résumés dans Personal blog -from-ruby /) Donc, si vous êtes intéressé, veuillez le vérifier.

Une brève introduction au fonctionnement du module virtuel à l'aide de REPL

Ici, j'utiliserai REPL pour écrire comment le module virtuel fonctionne en interne. On suppose que les éléments suivants sont déjà installés sur votre système:

Tout d'abord, lancez irb.

debussy:~ remore$ irb -r virtual_module
irb(main):001:0> po = VirtualModule.new(:python=>["sklearn"=>"datasets"])
=> #<Module:0x007fb7e1aee818>

L'appel de «VirtualModule # new» lance un processus Python (ou Julia) dans les coulisses. Lorsque le lancement du travail en arrière-plan a réussi, VirtualModule renvoie une nouvelle instance de Module. Désormais, nous communiquerons avec l'arrière-plan via cette instance de Module (≒ cette instance se comporte comme un proxy). Pour plus de commodité, nous appellerons cela un objet proxy.

irb(main):002:0> py.int(2.3)
=> 2
irb(main):003:0> po.unknown_method(2.3)
RuntimeError: An error occurred while executing the command in python process: ,name 'unknown_method' is not defined

Le comportement de l'objet proxy est très simple. Dans l'exemple ci-dessus, l'objet proxy reçoit un appel de méthode appelé ʻint (2.3) ʻet le transmet au travail d'arrière-plan tel quel (à ce moment, msgpack est utilisé pour convertir la valeur). En conséquence, la valeur de type Fixnum «2» est sortie vers le terminal, qui est renvoyée par le travail en arrière-plan. Puisque la conversion de données n'utilise que msgpack, les valeurs qui peuvent être converties les unes aux autres sont également conformes aux spécifications de msgpack. Si une méthode non définie est appelée du côté du travail d'arrière-plan, comme dans l'exemple po.unknown_method (2.3), une erreur sera affichée. Fondamentalement, ce qui précède est tout le fonctionnement du module virtuel.

Je pense qu'il y a des endroits que je ne peux pas m'empêcher d'ajouter un peu plus.

irb(main):004:0> po.datasets
=> #<Module:0x007ffd0906c030>
irb(main):005:0> po.datasets.load_iris(:_)
=> #<Module:0x007ffd09074500>
irb(main):006:0> po.datasets.load_iris(:_).vclass
=> "<class 'sklearn.datasets.base.Bunch'>"
irb(main):007:0> po.datasets.load_iris(:_).data[1].to_a
=> [4.9, 3.0, 1.4, 0.2]

Consultez cet exemple pour voir comment cela fonctionne lorsque des valeurs qui ne peuvent pas être réellement converties par msgpack sont utilisées. Dans cet exemple, l'objet proxy (la variable locale po ici) retourne d'abord un nouvel objet proxy (# <Module: 0x007ffd0906c030>) en réponse à l'appel de la méthode # datasets, mais après cela #load_iris (: _) renvoie également un autre objet proxy (# <Module: 0x007ffd09074500>). Étant donné que les ensembles de données sont des objets de type module sur Python, et load_iris (: _) est une instance de la classe `` 'sklearn.datasets.base.Bunch' ', aucun ne peut être converti via msgpack, donc l'instance Module est A été généré. Pour les appels qui ne peuvent pas être convertis par mspgack de cette manière, la valeur réelle n'est pas transmise à VirtualModule et seul un pointeur vers cette valeur est passé.

irb(main):008:0> po.datasets.vclass
=> "<type 'module'>"
irb(main):009:0> iris = po.datasets.load_iris(:_)
=> #<Module:0x007ffd09057568>
irb(main):010:0> iris.target.vclass
=> "<type 'numpy.ndarray'>"
irb(main):011:0> iris.target.vmethods
=> ["T", "__abs__", "__add__", "__and__", "__array__", "__array_finalize__", "__array_interface__", "__array_prepare__", "__array_priority__", "__array_struct__", "__array_wrap__", "__class__", "__contains__", "__copy__", "__deepcopy__", "__delattr__", "__delitem__", "__delslice__", "__div__", "__divmod__", "__doc__", "__eq__", "__float__", "__floordiv__", "__format__", "__ge__", "__getattribute__", "__getitem__", "__getslice__", "__gt__", "__hash__", "__hex__", "__iadd__", "__iand__", "__idiv__", "__ifloordiv__", "__ilshift__", "__imod__", "__imul__", "__index__", "__init__", "__int__", "__invert__", "__ior__", "__ipow__", "__irshift__", "__isub__", "__iter__", "__itruediv__", "__ixor__", "__le__", "__len__", "__long__", "__lshift__", "__lt__", "__mod__", "__mul__", "__ne__", "__neg__", "__new__", "__nonzero__", "__oct__", "__or__", "__pos__", "__pow__", "__radd__", "__rand__", "__rdiv__", "__rdivmod__", "__reduce__", "__reduce_ex__", "__repr__", "__rfloordiv__", "__rlshift__", "__rmod__", "__rmul__", "__ror__", "__rpow__", "__rrshift__", "__rshift__", "__rsub__", "__rtruediv__", "__rxor__", "__setattr__", "__setitem__", "__setslice__", "__setstate__", "__sizeof__", "__str__", "__sub__", "__subclasshook__", "__truediv__", "__xor__", "all", "any", "argmax", "argmin", "argpartition", "argsort", "astype", "base", "byteswap", "choose", "clip", "compress", "conj", "conjugate", "copy", "ctypes", "cumprod", "cumsum", "data", "diagonal", "dot", "dtype", "dump", "dumps", "fill", "flags", "flat", "flatten", "getfield", "imag", "item", "itemset", "itemsize", "max", "mean", "min", "nbytes", "ndim", "newbyteorder", "nonzero", "partition", "prod", "ptp", "put", "ravel", "real", "repeat", "reshape", "resize", "round", "searchsorted", "setfield", "setflags", "shape", "size", "sort", "squeeze", "std", "strides", "sum", "swapaxes", "take", "tobytes", "tofile", "tolist", "tostring", "trace", "transpose", "var", "view"]
irb(main):012:0> iris.target.to_a
=> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

Dans Ruby, vous pouvez obtenir des informations sur différents états d'un objet avec ʻObject # class et ʻObject # methods, mais VirtualModule suit cela avec des méthodes similaires (# vclass et # vmethods. `) Est prêt. Comme vous pouvez l'imaginer, «# vclass» visite le travail d'arrière-plan et renvoie le type de cette valeur, et «# vmethods» renvoie les méthodes disponibles pour cet objet.

C'est tout pour l'explication jusqu'à présent, mais si quelqu'un veut voir plus d'exemples, j'ai quelques autres exemples sur GitHub Vous pouvez vous y référer dans / tree / master / example). C'est une implémentation expérimentale, donc je pense que c'est difficile à utiliser dans de nombreux endroits, mais si quelqu'un veut l'utiliser, je serais heureux si vous pouviez me dire ce que vous en pensez.

Recommended Posts

Comment appeler Python ou Julia à partir de Ruby (implémentation expérimentale)
Méthodes MessagePack-Call Python (ou Python vers Ruby) à partir de Ruby à l'aide de RPC
[Python] Comment appeler une fonction de c depuis python (édition ctypes)
Appelez Matlab depuis Python pour optimiser
Appeler popcount depuis Ruby / Python / C #
Comment accéder à wikipedia depuis python
Comment appeler PyTorch dans Julia
Comment écrire un exemple d'implémentation E11 Ruby et Python en temps réel hors ligne
Comment mettre à jour Google Sheets à partir de Python
Comment accéder à RDS depuis Lambda (python)
Comment profiter de la programmation avec Minecraft (Ruby, Python)
Comment ouvrir un navigateur Web à partir de python
[Python] Conversion de DICOM en PNG ou CSV
[Python] Comment lire les données de CIFAR-10 et CIFAR-100
Comment générer un objet Python à partir de JSON
Un moyen simple d'appeler Java depuis Python
Comment installer Python
Changements de Python 3.0 à Python 3.5
Changements de Python 2 à Python 3.0
Python depuis ou import
[Python] Comment supprimer les valeurs en double de la liste
Comment récupérer des données d'image de Flickr avec Python
Comment mesurer le temps de traitement avec Python ou Java
Comment télécharger des fichiers depuis Selenium of Python dans Chrome
Exécuter la fonction Python à partir de Powershell (comment passer des arguments)
python, php, ruby Comment convertir un décimal en n
Comment gérer JSON en Ruby, Python, JavaScript, PHP
Un mécanisme pour appeler des méthodes Ruby à partir de Python qui peut être fait en 200 lignes
Appeler des fonctions du langage C depuis Python pour échanger des tableaux multidimensionnels
Appeler CPLEX depuis Python (DO cplex)
Publier de Python vers Slack
Comment installer Python [Windows]
python3: Comment utiliser la bouteille (2)
Comment écrire un exemple d'implémentation E14 Python en temps réel hors ligne
Flirter de PHP à Python
Comment découper un bloc de plusieurs tableaux à partir d'un multiple en Python
Comment exécuter un programme Python à partir d'un script shell
Comment utiliser la méthode __call__ dans la classe Python
Ne perdez pas contre Ruby! Comment exécuter Python (Django) sur Heroku
Comment appeler une fonction
Comment mettre à jour Tkinter de Python vers la version 8.6
Comment lancer AWS Batch à partir de l'application cliente Python
Comment se connecter à diverses bases de données à partir de Python (PEP 249) et SQL Alchemy
Anaconda mis à jour de 4.2.0 à 4.3.0 (python3.5 mis à jour vers python3.6)
Comment utiliser Python Argparse
Comment échantillonner à partir de n'importe quelle fonction de densité de probabilité en Python
[Python] Comment utiliser checkio
[Python / Ruby] Comprendre le code Comment obtenir des données en ligne et les écrire au format CSV
Passer de python2.7 à python3.6 (centos7)
Comment exécuter Notepad ++ Python
Connectez-vous à sqlite depuis python
Comment changer la version de Python
[python] Comment juger scalaire
[Python] Comment utiliser input ()
Comment utiliser Python lambda
[Python] Comment utiliser virtualenv
python3: Comment utiliser la bouteille (3)
python3: Comment utiliser la bouteille
Aller au langage pour voir et se souvenir de la partie 8 Appeler le langage GO à partir de Python