Subscript out of bounds - general definition and solution?
Asked Answered
T

6

82

When working with R I frequently get the error message "subscript out of bounds". For example:

# Load necessary libraries and data
library(igraph)
library(NetData)
data(kracknets, package = "NetData")

# Reduce dataset to nonzero edges
krack_full_nonzero_edges <- subset(krack_full_data_frame, (advice_tie > 0 | friendship_tie > 0 | reports_to_tie > 0))

# convert to graph data farme 
krack_full <- graph.data.frame(krack_full_nonzero_edges) 

# Set vertex attributes
for (i in V(krack_full)) {
    for (j in names(attributes)) {
        krack_full <- set.vertex.attribute(krack_full, j, index=i, attributes[i+1,j])
    }
}

# Calculate reachability for each vertix
reachability <- function(g, m) {
    reach_mat = matrix(nrow = vcount(g), 
                       ncol = vcount(g))
    for (i in 1:vcount(g)) {
        reach_mat[i,] = 0
        this_node_reach <- subcomponent(g, (i - 1), mode = m)

        for (j in 1:(length(this_node_reach))) {
            alter = this_node_reach[j] + 1
            reach_mat[i, alter] = 1
        }
    }
    return(reach_mat)
}

reach_full_in <- reachability(krack_full, 'in')
reach_full_in

This generates the following error Error in reach_mat[i, alter] = 1 : subscript out of bounds.

However, my question is not about this particular piece of code (even though it would be helpful to solve that too), but my question is more general:

  • What is the definition of a subscript-out-of-bounds error? What causes it?
  • Are there any generic ways of approaching this kind of error?
Terret answered 22/2, 2013 at 19:0 Comment(2)
@Locus has it. It means you're trying to get something, say a column or row, that doesn't exist. For example, say your table has 10 rows and your function tries to call for row 15.Fetation
And for anyone who's wondering about this PARTICULAR piece of code (from the McFarland network analysis labs) it's because igraph has changed its indexing scheme from 0-based to 1-based, and so '(i-1)' in 'subcomponent' should be just 'i'.Inartistic
C
115

This is because you try to access an array out of its boundary.

I will show you how you can debug such errors.

  1. I set options(error=recover)
  2. I run reach_full_in <- reachability(krack_full, 'in') I get :

    reach_full_in <- reachability(krack_full, 'in')
    Error in reach_mat[i, alter] = 1 : subscript out of bounds
    Enter a frame number, or 0 to exit   
    1: reachability(krack_full, "in")
    
  3. I enter 1 and I get

     Called from: top level 
    
  4. I type ls() to see my current variables

      1] "*tmp*"           "alter"           "g"               
         "i"               "j"                     "m"              
        "reach_mat"       "this_node_reach"
    

Now, I will see the dimensions of my variables :

Browse[1]> i
[1] 1
Browse[1]> j
[1] 21
Browse[1]> alter
[1] 22
Browse[1]> dim(reach_mat)
[1] 21 21

You see that alter is out of bounds. 22 > 21 . in the line :

  reach_mat[i, alter] = 1

To avoid such error, personally I do this :

  • Try to use applyxx function. They are safer than for
  • I use seq_along and not 1:n (1:0)
  • Try to think in a vectorized solution if you can to avoid mat[i,j] index access.

EDIT vectorize the solution

For example, here I see that you don't use the fact that set.vertex.attribute is vectorized.

You can replace:

# Set vertex attributes
for (i in V(krack_full)) {
    for (j in names(attributes)) {
        krack_full <- set.vertex.attribute(krack_full, j, index=i, attributes[i+1,j])
    }
}

by this:

##  set.vertex.attribute is vectorized!
##  no need to loop over vertex!
for (attr in names(attributes))
      krack_full <<- set.vertex.attribute(krack_full, 
                                             attr, value = attributes[,attr])
Cy answered 22/2, 2013 at 19:16 Comment(3)
I think you need first options(error=function() dump.frames(to.file=TRUE)) to have the error logs somewhere.Geny
Very useful, this debugging thing. I my case, it allowed me to find out that the "subscript out of bounds" error was apparently due to me using a "factor" instead of a character to access a matrix column by name. as.character solved my problem. Strange thing is that the bugged code is part of a library that I successfully used on similar data.Elin
@Elin maybe you are using some new versions of some packages that no more support factor.Cy
L
6

It just means that either alter > ncol( reach_mat ) or i > nrow( reach_mat ), in other words, your indices exceed the array boundary (i is greater than the number of rows, or alter is greater than the number of columns).

Just run the above tests to see what and when is happening.

Locus answered 22/2, 2013 at 19:7 Comment(0)
S
5

Only an addition to the above responses: A possibility in such cases is that you are calling an object, that for some reason is not available to your query. For example you may subset by row names or column names, and you will receive this error message when your requested row or column is not part of the data matrix or data frame anymore. Solution: As a short version of the responses above: you need to find the last working row name or column name, and the next called object should be the one that could not be found. If you run parallel codes like "foreach", then you need to convert your code to a for loop to be able to troubleshoot it.

Settles answered 22/8, 2017 at 20:31 Comment(0)
S
5

If this helps anybody, I encountered this while using purr::map() with a function I wrote which was something like this:

find_nearby_shops <- function(base_account) {
   states_table %>% 
        filter(state == base_account$state) %>% 
        left_join(target_locations, by = c('border_states' = 'state')) %>% 
        mutate(x_latitude = base_account$latitude,
               x_longitude = base_account$longitude) %>% 
        mutate(dist_miles = geosphere::distHaversine(p1 = cbind(longitude, latitude), 
                                                     p2 = cbind(x_longitude, x_latitude))/1609.344)
}

nearby_shop_numbers <- base_locations %>% 
    split(f = base_locations$id) %>% 
    purrr::map_df(find_nearby_shops) 

I would get this error sometimes with samples, but most times I wouldn't. The root of the problem is that some of the states in the base_locations table (PR) did not exist in the states_table, so essentially I had filtered out everything, and passed an empty table on to mutate. The moral of the story is that you may have a data issue and not (just) a code problem (so you may need to clean your data.)

Thanks for agstudy and zx8754's answers above for helping with the debug.

Somebody answered 23/1, 2019 at 19:3 Comment(0)
B
2

I sometimes encounter the same issue. I can only answer your second bullet, because I am not as expert in R as I am with other languages. I have found that the standard for loop has some unexpected results. Say x = 0

for (i in 1:x) {
  print(i)
}

The output is

[1] 1
[1] 0

Whereas with python, for example

for i in range(x):
  print i

does nothing. The loop is not entered.

I expected that if x = 0 that in R, the loop would not be entered. However, 1:0 is a valid range of numbers. I have not yet found a good workaround besides having an if statement wrapping the for loop

Boondoggle answered 22/2, 2013 at 19:19 Comment(1)
Which is why you don't do for (i in 1:x) for an x that could be zero (it does what it should given the definitions, that's just not what you hoped it would do). You do for (seq_len(x)) to get the behaviour you seek.Hurleigh
A
1

This came from standford's sna free tutorial and it states that ...

# Reachability can only be computed on one vertex at a time. To # get graph-wide statistics, change the value of "vertex" # manually or write a for loop. (Remember that, unlike R objects, # igraph objects are numbered from 0.)

ok, so when ever using igraph, the first roll/column is 0 other than 1, but matrix starts at 1, thus for any calculation under igraph, you would need x-1, shown at

this_node_reach <- subcomponent(g, (i - 1), mode = m)

but for the alter calculation, there is a typo here

alter = this_node_reach[j] + 1

delete +1 and it will work alright

Affiliate answered 5/3, 2013 at 14:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.