Vetorizando como um (semi) profissional | R-bloggers

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br


[Esteartigofoipublicadopelaprimeiravezem[Thisarticlewasfirstpublishedon Data Imaginist, e gentilmente contribuiu para os R-blogueiros]. (Você pode relatar um problema sobre o conteúdo desta página aqui)


Deseja compartilhar seu conteúdo com R-blogueiros? clique aqui se você tiver um blog ou aqui se não tiver.

Este é um pequeno post prático sobre como programar com R. Leve-o para o que
é e nada mais …

R é lento! É isso que eles continuam nos dizendo (eles ser alguém que “sabe”
sobre programação “real” e tem outra linguagem que, por algum motivo, falha
ser crítico sobre).

R é uma coisa estranha. Especialmente para pessoas que foram treinadas em um clássico
linguagem de programação. Uma das principais razões para isso é sua natureza vetorizada,
que não é apenas o fato de que os vetores são predominantes no idioma, mas
é um princípio subjacente que deve orientar o design de algoritmos eficientes
no idioma Se você escreve R, como escreve C (ou Python), verifique se é
lento, mas realmente, você está apenas usando errado.

Este post o guiará pelo design de uma função vetorizada. A gênese
da função vem da minha arte generativa, mas achei tão legal e
independente de que seria uma boa postagem no blog. Se isso parece algo
que poderia tirar sua mente da pandemia e apertar o cinto!

O problema

Eu tenho um mapa de altura, ou seja, uma matriz de valores numéricos. Você sabe o que? Vamos
torne isso concreto e crie um:

library(ambient)
library(dplyr)

z % 
  mutate(val = gen_simplex(x, y, frequency = 0.02)) %>% 
  as.matrix(val)

image(z, useRaster = TRUE)

Isso é apenas um ruído simplex, é claro, mas se encaixa no nosso propósito…

De qualquer forma, temos um mapa de altura e queremos encontrar os extremos locais, ou seja, o
local mínimo e máximo. É isso aí. Bastante simples e compreensível
desafio certo.

Vetorizado, smecktorised

Agora, se você fosse um programador C treinado, provavelmente teria resolvido isso
com um laço. É assim que deve ser feito em C, mas aplicá-lo ao R irá
resultar em um programador muito irritado que dirá a quem se interessar em ouvir
esse R é lento.

Leia Também  Visualização de redes multiníveis com layouts de gráficos

Nós já sabíamos disso. Queremos algo vetorizado, certo? Mas o que é
vetorizado de qualquer maneira? Em toda a internet, a recomendação é usar o
apply()-família de função para vetorizar seu código, mas tenho más notícias
para você: esta é a maneira absolutamente errada de vetorizar. Há muitas coisas boas
razões para usar a abordagem funcional do loop em vez do loop for, mas
quando se trata de R, o desempenho não é um deles.

Merda…

Para descobrir isso, precisamos ser um pouco mais claros sobre o que queremos dizer com um
função vetorizada. Existem algumas maneiras diferentes de pensar sobre isso

  1. A definição ampla e preguiçosa é uma função que opera nos elementos de
    um vetor Aqui é onde apply() (e amigos) residem funções baseadas.
  2. A definição estreita e de desempenho é uma função que opera no
    elementos de um vetor no código compilado. É aqui que muitos da base de R
    funções vivem junto com funções projetadas corretamente implementadas em C ou C ++
  3. O meio termo é uma função composta de chamadas para 2) evitar
    loops explícitos, adiando assim a maioria das operações de elementos para código compilado.

Queremos falar sobre 3). Simplesmente implementar isso no código compilado seria
trapacear e não aprenderíamos nada.

Pensando com vetores

R vem com muitas baterias incluídas. Algumas das funções de mais alto nível
não são implementadas com o desempenho em mente (infelizmente), mas muitas das
o material é, por exemplo indexação, aritmética, somatórios, etc. Acontece que esses
muitas vezes são suficientes para implementar funções bastante complexas de maneira eficiente
maneira vetorizada.

Voltando ao nosso problema inicial de encontrar extremos: o que efetivamente somos
pedir é uma função de janela em movimento em que cada célula é avaliada se
é o maior ou menor valor em sua respectiva janela. Se você pensa um pouco
sobre isso, isso é principalmente uma questão de indexação. Para cada elemento na matriz,
queremos os índices de todas as células dentro de sua janela. Uma vez que temos isso, é
bastante fácil extrair todos os valores relevantes e usar o vetorizado pmin()
e pmax() para descobrir o valor máximo na janela e usar o botão
(vetorizado) == para ver se o extremo é equivalente ao valor da célula.

Leia Também  wrapr 2.0.0 up no CRAN

Isso é muita conversa, aqui está a função final:

extrema  n_rows | col  n_cols] 

(não se preocupe, vamos analisar isso daqui a pouco)

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br

Essa função pega uma matriz e um raio de vizinhança e retorna uma nova matriz
das mesmas dimensões que a entrada, com 1 no máximo local, -1 no
mínimos locais e em qualquer outro lugar.

Vamos passar por isso:

# ...
  ind 

Aqui, estamos simplesmente fazendo alguns cálculos rápidos para reutilização mais tarde. o
A variável ind é simplesmente o índice para cada célula na matriz. Matrizes são
simplesmente vetores embaixo, para que eles também possam ser indexados dessa maneira. rows e
cols mantém o índice de linha e coluna de cada célula e n_rows e n_cols
são bastante auto-explicativos.

# ...
  window_offsets 

A maior parte da mágica acontece aqui, mas não é tão aparente. O que fazemos é que
nós usamos o outer() função para construir uma matriz, o tamanho da nossa janela,
segurando o deslocamento do índice do centro para cada uma das células na janela. Nós
também constrói vetores segurando as linhas e o deslocamento da coluna para cada célula

# ...
  windows  n_rows | col  n_cols] 

É aqui que toda a mágica parece acontecer. Para cada célula na janela, nós
estão calculando seu respectivo valor para cada célula na matriz de entrada. eu posso
já ouvi você gritar sobre mim usando e apply()função, mas a tecla
O fato é que não o estou usando para fazer um loop sobre os elementos do vetor de entrada (ou
matriz), mas com um número muito menor (e geralmente fixo) de elementos.

Se você quiser sair agora, porque estou movendo as postagens do meu convidado.

De qualquer forma, o que está acontecendo dentro do mapply() ligar? Dentro da função nós
descobrir de que linha e coluna a célula deslocada faz parte. Então calculamos
o índice das células para o deslocamento. Para se proteger contra fora dos limites
erros, definimos todos os índices que estão fora do limite de NAe então simplesmente
índice em nossa matriz. A parte crucial é que todas as operações aqui são
vetorizado (indexação, aritmética e comparações). No final, temos uma lista
segurando vetores de valores para cada célula na janela.

# ..
  windows 

Isso é realmente apenas finalização, mesmo que os cálculos reais sejam
acontecendo aqui. Nós usamos pmin() e pmax() para encontrar o máximo e o mínimo
em cada janela e compare-o com o valor em nossa matriz de entrada (novamente, todos
função vetorizada adequada). No final, construímos uma matriz segurando areia
use as posições calculadas para definir 1 ou -1 no local do local
extremos.

Leia Também  Empresa de consultoria Avonhurst contrata novo chefe de relacionamentos de rede

Funciona?

Eu acho que essa é a pergunta de um milhão de dólares, seguida de perto por “é
Mais rápido?”. Eu realmente não me importo o suficiente para implementar uma vetorização “burra”, então
Vou colocar minha cabeça no bloco com a última pergunta e insistir que, sim,
é muito mais rápido. Você pode tentar me bater com um apply() solução baseada e
Vou comer um adesivo se você conseguir (a menos que trapaceie).

Quanto à primeira pergunta, vamos dar uma olhada

extremes 

Eis que parece que conseguimos.

A vetorização pode salvar o mundo?

Não…

Mais exatamente, nem todo problema tem uma boa solução vetorizada. Mais longe,
A grande desvantagem com a vetorização adequada é que muitas vezes requer a expansão de um
muitas variáveis ​​para o tamanho do vetor de entrada. No nosso caso, precisávamos segurar
todas as janelas na memória simultaneamente e não é preciso muita imaginação
para pensar em cenários em que isso possa fazer nosso computador explodir. Ainda mais
Muitas vezes, é possível escrever código R de alto desempenho e, geralmente, o
parte crucial é descobrir como fazer uma indexação inteligente.

Se você ainda não está convencido, leia
Blog de Brodie Gaslam. Ele tem uma propensão para
implementando coisas ridiculamente complicadas em R altamente eficiente
código. Escusado será dizer que suas postagens costumam ser mais envolvidas do que isso,
mas se você continuou lendo até agora, acho que está pronto …



Se você chegou até aqui, por que não inscreva-se para atualizações do site? Escolha seu sabor: e-mail, Twitter, RSS ou facebook …



cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br