La ley de Benford, revisitada
Revisito mi artículo sobre la ley de Benford no tanto por hacer mención a las entradas una, dos y tres que hizo Gregorio Serrano en su bitácora ni al oportunísimo artículo de The Guardian al respecto. Ni siquiera para mencionar la existencia de este sesudo artículo sobre el tema.
Lo hago porque me pliego a la demanda popular: voy a explicar con más detalle el código que dejé allí escrito y que, por referencia, es
benford <- function( foo, ..., n = 100000 ){
tmp <- foo( n, ... )
tmp <- as.character( tmp[ tmp > 0] )
tmp <- strsplit( tmp, "" )
leading.digit <- function( x )
x[ ! x %in% c( "0", "." )][1]
tmp <- unlist( lapply( tmp, leading.digit ) )
100 * table( tmp ) / length( tmp )
}
benford( rcauchy )
benford( rexp, rate = 2 )
benford( rexp, rate = 5 )
benford( rnorm, sd = 40 )
benford( rweibull, shape = 1 )
Puede llamar la atención que el primer argumento de la función benford
sea, precisamente, otra función. Nada del otro mundo. El siguiente es un ejemplo en el que se muestra el uso aislado para una mejor comprensión:
funcion.que.llama <- function( foo, ... ){
foo(...)
}
funcion.que.llama( sin, 2*pi )
funcion.que.llama( plot, iris, main = "Hola" )
La función funcion.que.llama
recibe una función como argumento. También recibe argumentos adicionales arbitrarios (eso es lo que significa ...
). Dentro, además de llamar a la función elegida, le pasa los argumentos adicionales contenidos en ...
. Es su uso más habitual, según el documento que define R.
Después uso las funciones as.character
(para convertir el número en una cadena de texto) y strsplit
, función análoga a la que existe en otros lenguajes. Su particularidad en R es que, aplicada a un vector de caracteres, devuelve una lista de la misma longitud que el vector original. No hay más que saber sobre dicha función que entender cuál es la salida de
strsplit( c("Hola", "caracola"), "l")
Como strsplit
devuelve una lista, resulta conveniente utilizar lapply
para recorrerla y extraer de cada componente el primer caracter. La lógica de lo que se quiere hacer en cada componente está encapsulada en la función de usar y tirar leading.digit
.
Finalmente, como lapply
devuelve una lista, utilizo unlist
para convertirla en una estructura más simple, un vector de characters
sobre el que utilizo la función table
para calcular las frecuencias.
En resumen, llamo a las funciones as.character
, strsplit
y table
porque sirven para mis fines: aportan el contenido semántico. Las llamadas a lapply
y unlist
no tienen otro objeto que facilitar la manipulación de los objetos que devuelven las anteriores. Son, si se quiere decir así, pegamento sintáctico.