ti-enxame.com

Subscrito fora dos limites - definição geral e solução?

Ao trabalhar com R, frequentemente recebo a mensagem de erro "subscrito fora dos limites". Por exemplo :

# 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

Isso gera o seguinte erro Error in reach_mat[i, alter] = 1 : subscript out of bounds.

No entanto, minha pergunta não é sobre esse trecho de código específico (mesmo que seja útil resolver isso também), mas minha pergunta é mais geral:

  • Qual é a definição de um erro de subscrito fora dos limites? O que causa isso?
  • Existem formas genéricas de abordar esse tipo de erro?
45
histelheim

Isso ocorre porque você tenta acessar uma matriz fora de seus limites.

Vou mostrar como você pode depurar esses erros.

  1. Eu defino options(error=recover)
  2. Eu corro reach_full_in <- reachability(krack_full, 'in') eu recebo:

    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. Eu digito 1 e recebo

     Called from: top level 
    
  4. Digite ls() para ver minhas variáveis ​​atuais

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

Agora, vou ver as dimensões das minhas variáveis:

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

Você vê que o alter está fora dos limites. 22> 21. na linha :

  reach_mat[i, alter] = 1

Para evitar esse erro, pessoalmente faço isso:

  • Tente usar a função applyxx. Eles são mais seguros que for
  • Eu uso seq_along e não 1:n (1: 0)
  • Tente pensar em uma solução vetorizada se puder evitar o acesso ao índice mat[i,j].

EDITAR vetorize a solução

Por exemplo, aqui vejo que você não usa o fato de que set.vertex.attribute é vetorizado.

Você pode substituir:

# 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])
    }
}

por este:

##  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])
75
agstudy

Se isso ajuda alguém, eu encontrei isso ao usar purr :: map () com uma função que escrevi que era algo como isto:

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) 

Às vezes, recebia esse erro com amostras, mas na maioria das vezes não. A raiz do problema é que alguns dos estados na tabela base_locations (PR) não existiam na tabela states_, portanto, basicamente eu havia filtrado tudo e passado uma tabela vazia para sofrer uma mutação. A moral da história é que você pode ter um problema de dados e não (apenas) um problema de código (portanto, pode ser necessário limpar seus dados.)

Obrigado pelas respostas do agstudy e do zx8754 acima, por ajudar na depuração.

3
John Paul Cassil

Significa apenas que alter > ncol( reach_mat ) ou i > nrow( reach_mat ), em outras palavras, seus índices excedem o limite da matriz (i é maior que o número de linhas ou alter é maior que o número de colunas).

Basta executar os testes acima para ver o que e quando está acontecendo.

3
January

Às vezes encontro o mesmo problema. Só posso responder ao seu segundo marcador, porque não sou tão experiente em R quanto em outros idiomas. Eu descobri que o loop for padrão tem alguns resultados inesperados. Diga x = 0

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

A saída é

[1] 1
[1] 0

Considerando que com python, por exemplo

for i in range(x):
  print i

faz nada. O loop não é inserido.

Eu esperava que se x = 0 que em R, o loop não seria inserido. No entanto, 1:0 é um intervalo válido de números. Ainda não encontrei uma boa solução alternativa, além de ter uma instrução if envolvendo o loop for

2
James Pringle

Isso veio do tutorial gratuito sna de standford e afirma que ...

# 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, sempre que usar igraph, o primeiro rolo/coluna é 0 diferente de 1, mas a matriz começa em 1, portanto, para qualquer cálculo no igraph, você precisaria de x-1, mostrado em

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

mas para o cálculo da alteração, há um erro de digitação aqui

alter = this_node_reach[j] + 1

excluir +1 e funcionará bem

1
YangJ

Apenas uma adição às respostas acima: Uma possibilidade nesses casos é que você esteja chamando um objeto que, por algum motivo, não esteja disponível para sua consulta. Por exemplo, você pode definir um subconjunto por nomes de linhas ou nomes de colunas e receberá essa mensagem de erro quando a linha ou coluna solicitada não fizer mais parte da matriz ou quadro de dados. Solução: Como uma versão curta das respostas acima: você precisa encontrar o último nome da linha em funcionamento ou o nome da coluna, e o próximo objeto chamado deve ser aquele que não foi encontrado. Se você executar códigos paralelos como "foreach", precisará converter seu código em um loop for para poder solucioná-lo.

1
Farshad