3  Pitfalls when using both Python and R

Python and R are very different programming languages. Here are some pitfalls you might encounter when mixing both languages.

3.1 Column major vs row major

Matrices are stored contiguously in-memory, and are adressed by a single memory addresses, instead of multiple indices along the axis. A translation needs to happen between this single adress and the indices along the axes, and how that translation happens depens on how the matrix is represented in-memory.

The figure below illustrates the most common ways a matrix is stored in memory, column major and row major order.

Figure 3.1: Different in-memory representations

In R, every dense matrix is represented in column major order. In Python, the standard is row major, but you can specify column major order as well. There is usually no issue when converting R matrices to Python matrices: reticulate will take care to present these as column major Python matrices. The reverse is not true: all dense (even row major) Python matrices are presented to R as column major matrices.

If you notice something amiss with your matrices, check whether you need to transpose them or change the row/column major attribute.

3.2 Indexing: 0-based or 1-based

Take care to remember that arrays and matrices in Python are indexed starting from 0 (as in, index 0 refers to the first element), while R uses 1-based indexing, where index 1 refers to the first element.

Figure 3.2: 0-based vs 1-based indexing

3.3 Dots in variable names

In R it is very common to use dots in symbols and variable names. This is invalid in Python: dots are used for function calls.

When using rpy2, these dots are usually translated to underscores _. If this translation can result in errors, this does not happen automatically. In this case, you can specify mappings for these symbols.

from rpy2.robjects.packages import importr
/home/runner/work/polygloty/polygloty/renv/python/virtualenvs/renv-python-3.12/lib/python3.12/site-packages/rpy2/rinterface_lib/embedded.py:276: UserWarning: R was initialized outside of rpy2 (R_NilValue != NULL). Trying to use it nevertheless.
  warnings.warn(msg)
R was initialized outside of rpy2 (R_NilValue != NULL). Trying to use it nevertheless.

d = {'package.dependencies': 'package_dot_dependencies',
     'package_dependencies': 'package_uscore_dependencies'}
tools = importr('tools', robject_translations = d)

3.4 Integers and floating point numbers

Unless you explicitely specify, any number is represented as a floating point number in R. By adding a L at the end of the number, you specify that it is an integer.

Python is usually more strict about using integers or floating point numbers than R.

float_ex <- 12
int_ex <- 12L

is.integer(float_ex)
[1] FALSE
is.integer(int_ex)
[1] TRUE

This can often lead to errors when using reticulate! If you’re calling a Python function and provide it with just a number in R, it probably won’t be recognised as an integer, leading to errors:

library(reticulate)
bi <- reticulate::import_builtins()

bi$list(bi$range(0, 5))
'float' object cannot be interpreted as an integer

As you can see, you get errors: TypeError: 'float' object cannot be interpreted as an integer.

This is easily fixed by specifiying integers:

bi$list(bi$range(0L, 5L))
[1] 0 1 2 3 4