-1

I am struggling with the following issue. I trained a model and loaded the trained model in R as follows:

model <- readRDS("C://tests/my_model.rds")
result <- predict(model, trainset, type = "prob")[, 2]

Everything works well and I can get the predictions.

trainset =
   col1    col2    col2
   1       0       1

However, when I try to call the same model using pyper from R, I get this message:

TypeError: object of type 'NoneType' has no len()

In particular, expr = 'model <- readRDS(rmodel); result <- predict(model, rdata, type="prob")[,2]' seems to return None.

This is my code:

import json
import numpy as np
import pandas as pd
from pyper import R

def init():
    global r
    r=R(RCMD="C://Program Files/R/R-3.6.2/bin/x64/R.exe", use_pandas=True)
    rds_path = "C://tests/my_model.rds"
    r.assign("rmodel", rds_path)

def run(raw_data, request_headers):
    data = json.loads(raw_data)["data"]
    cols = json.loads(raw_data)["cols"]
    data = pd.DataFrame(np.array(data), columns = cols)
    r.assign("rdata", data)
    expr = 'model <- readRDS(rmodel); result <- predict(model, rdata, type="prob")[,2]'
    r(expr)
    result = r.get('result')

    print(('{{"RequestId":"{0}", '
       '"TraceParent":"{1}", '
       '"NumberOfPredictions":{2}}}'
       ).format(
           request_headers.get("X-Ms-Request-Id", ""),
           request_headers.get("Traceparent", ""),
           len(result)
       ))

    return {"result": result.tolist()}

This is how I call the functions:

init()
test_row = '{"data":[[1,0,1]],"cols":[["col1","col2","col3"]]}'
prediction = run(test_row, {})
print("Test result: ", prediction)

I will really appreciate any help on detecting the issue because the error message is not very informative…

I make experiments in Jupyter Notebook.

Even when I try to substitute expr like this (dummy R code):

expr = 'p <- c(1,2); result <- p'

I get an error:

OSError                                   Traceback (most recent call last)
<ipython-input-97-240ae868eecb> in <module>
      3 test_row  = json.dumps(input_data)
      4 
----> 5 prediction = run(test_row, {})

<ipython-input-96-370705f72e83> in run(raw_data, request_headers)
     23         print(data.head())
     24 
---> 25     r.assign("rdata", data)
     26     expr = 'p <- rdata[1,1:2]; result <- [p]'
     27     r(expr)

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pyper.py in __setitem__(self, obj, val)
    692         if obj.startswith('_'):
    693             raise RError('Leading underscore ("_") is not permitted in R variable names!')
--> 694         self.__call__('%s <- %s' % (obj, Str4R(val)))
    695 
    696     def __delitem__(self, obj):  # to model a dict: "del r['XXX']"

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pyper.py in __call__(self, CMDS, use_try)
    646         rlt = []
    647         if isinstance(CMDS, basestring):  # a single command
--> 648             rlt.append(self.__runOnce(CMDS, use_try=use_try))
    649         else: # should be a list of commands
    650             # for CMD in CMDS:

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pyper.py in __runOnce(self, CMD, use_try)
    622             fn = fn.replace('\\', '/')
    623             CMD = (use_try and 'try({source("%s")})%sfile.remove(%r)%s%s' or '%s%s%s') % (fn, newline, fn, newline, tail_cmd)
--> 624         self.sendAll(self.prog, CMD)
    625         rlt = ''
    626         while not re_tail.search(rlt):

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pyper.py in sendAll(p, s)
    167         p.stdin.write(_mybytes(s))
    168         #os.write(p.stdin.fileno(), s)
--> 169         p.stdin.flush()
    170 
    171     def readLine(p, dump_stdout=False, *a, **b):

OSError: [Errno 22] Invalid argument
Fluxy
  • 2,838
  • 6
  • 34
  • 63
  • Why is it downvoted? – Fluxy Jan 30 '20 at 16:00
  • I didn't downvote it, but one guess would be your title doesn't match well your real issue. Python is just saying it cannot process measuring the length of an object that is of the variety `NoneType`, as `result` is. It wants something that has a length. Your real problem is earlier because your `r.get('result')` code is either implemented wrong or not working. – Wayne Jan 30 '20 at 16:16
  • @Wayne: Right, thanks. The real problem is that the prediction statement does not work for some reason, though as you can see from my R example the model is fine and the features are correct. It works in R, but returns None in Python. – Fluxy Jan 30 '20 at 16:27

2 Answers2

1

While I have not worked with pyper, I think your error is when you do r.assign("rmodel", rds_path). This should be used to assign an Python object, e.g. a pandas data-frame to the R instance to make it available (this is what you do in the run() function). However, in init() you only pass a String of a path, which is not an object.

I think, it will not be possible to read your R model directly into Python. But, you should try loading your model in the Python R instance instead. So translate this model <- readRDS("C://tests/my_model.rds") to pypyer. Then, your model should be available and able to make predictions.

mc51
  • 1,883
  • 14
  • 28
  • Thank you so much! I will give it a try and will let you know! – Fluxy Jan 30 '20 at 17:12
  • I tested it: `expr = 'model <- readRDS("C://tests/mymodel.rds"); result <- predict(model, rdata, probability=False)'`. But again `result` is None. I cannot understand what is happening. – Fluxy Jan 30 '20 at 17:20
  • Could you provide a [minimal, reproducible example?](https://stackoverflow.com/help/minimal-reproducible-example) Otherwise it's mostly guessing around. /e: Also, check if your model was loaded correctly by inspecting the model variable after you load it. Maybe, that's not the issue anymore. – mc51 Jan 30 '20 at 17:48
1

Check the data type returned by your R program. PypeR doesn't support all the datatypes of R and there might be some issue while converting non-primitive datatype, which is why your r.get() is returning None. Try converting the result generated in R to data.frame() or list() before returning data in R.

Rohit
  • 11
  • 1