jueves, 26 de abril de 2018

VBA: Método de Newton-Raphson en Excel

Un usuario planteaba dudas por cómo emplear en Excel el método de Newton-Raphson (ver Wikipedia) para resolver ecuaciones y encontrar su raíz.

Si trasladamos esos algoritmos de cálculo a nuestras macros, en modo de función, tendríamos las UDF que veremos a continuación...
El algoritmo se basa, de acuerdo a lo que se indica en Wikipedia, a un método recurrente geométrico... desarrollado a partir de otro método de cálculo (método de la secante).
Seguro que algún experto matemático podrá aportar mucho más al respecto.


En mi ejemplo, operaremos para obtener la raíz de la siguiente ecuación:
f(x)=LOG(x-1)+COS(x-1)

Nota: la función de VBA LOG equivale al logaritmo neperiano (o natural) en base e (2,718281828459)

y sabiendo que su función derivada es:
f'(x)=1/(x-1)-SIN(x-1)




En un módulo estándar del libro incluimos las siguientes UDF:

Function func(x) As Double
'Nuestra función a analizar
func = Math.Log(x - 1) + Math.Cos(x - 1)

End Function
Function func_derivada(x) As Double
'la derivada de nuestra función
func_derivada = 1 / (x - 1) - Math.Sin(x - 1)

End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function NewtonRaphson(x_0 As Double, tolerancia As Double, iteracionMax As Long)
'1er argumeto x_0: el valor inicial desde donde parte el recorrido buscando la raíz/solución.
'2do argumento tolerancia: el margen de error buscado.
'3er argumento iteraciónMax: el límite de iteraciones máximo permitido buscando la raíz/solución
Dim x_n1 As Double, x_n As Double
Dim error_dif As Double

Dim contador As Integer
x_n = x_0
contador = 0
'iniciamos el bucle...
Do
    'método Newton-Raphson
    x_n1 = x_n - func(x_n) / func_derivada(x_n)
    'paremetrizamos el error
    error_dif = x_n1 - x_n
    'y asignamos nuevo valor para el siguiente paso iterativo
    x_n = x_n1
    'incrementamos el contador para controlar una salida del bucle
    contador = contador + 1
Loop Until Math.Abs(error_dif) <= tolerancia Or contador = iteracionMax
'hemos salido del bucle si la diferencia entre los elementos es menor de la tolerancia determinada
' o la iteración llega al máximo indicado(iteracionMax).

'finalmente damos valor a nuestra función
NewtonRaphson = x_n1
End Function

Podemos verificar nuestra solución si insertamos en la celda C22 la fórmula: =NewtonRaphson(C3;0,000001;100)

VBA: Método de Newton-Raphson en Excel

Una alternativa, mediante funciones sin programación, es hacerlo directamente sobre la hoja de cálculo, como se ve en la imagen anterior.

En la celda C3 disponemos el primer valor a tomar 1,01 para nuestro ejemplo, y en la celdas sucesivas C4:C18 añadimos:

=C3-D3/E3

que respondería al algoritmo del método de Newton...

En las columnas C y D añadiríamos la formulación de la función principal y la función derivada, respectivamente para los valores obtenidos en la columna B.

En otro post, describiré el proceso manual.

Por otra parte, si hacemos la comprobación gráfica de la raíz, vemos que efectivamente, cuando x=1,397748475 la función f(x)=LOG(x-1)+COS(x-1) se hace cero.

VBA: Método de Newton-Raphson en Excel

martes, 24 de abril de 2018

Alto de fila y Ancho de columna

Vamos a configurar nuestro alto de fila y ancho de columna para nuestras hojas... dos aspectos frecuentes, que tocamos rutinariamente, pero del que desconocemos bastante.

Comencemos por el típico Ancho de columna.
Podemos configurar una o varias columnas, o todas las columnas de la hoja.
Basta seleccionar aquellas columnas que queremos afectar y con el clic derecho del ratón buscar la opción: Ancho de columna...

Alto de fila y Ancho de columna


En la ventana siguiente indicaremos el ancho deseado (ver post)

Otra posibilidad es acceder, en la cinta de opciones, a la Ficha Inicio > grupo Celdas > desplegable Formato

Alto de fila y Ancho de columna


Aquí disponemos, respecto del ancho de columna, de tres alternativas:
1-Ancho de columna...: equivalente a hacer clic derecho del ratón. Nos permite sobre las columnas seleccionados configurar el ancho.
2-Autoajustar ancho de columna: Se ajustará cada columna seleccionada al ancho necesario según los caracteres máximos existentes columna por columna.
3-Ancho predeterminado...: Sin necesidad de seleccionar nada en particular, aquí definiremos el ancho de todas las columnas de la hoja.


Todos estos cambios afectarán únicamente a la hoja activa, sobre la que realizamos las modificaciones!!.

Vamos ahora a por el Alto de fila.
Respecto del alto de fila podemos actuar de forma similar, i.e., seleccionamos una o varias filas, y al hacer clic derecho buscaremos la opción de Alto de fila..., y en la ventana diálogo siguiente indicaremos el alto deseado (ver post).

Alto de fila y Ancho de columna



Igualmente al ancho de columna también podemos acceder desde la Ficha Inicio > grupo Celdas > desplegable Formato

Alto de fila y Ancho de columna


Disponemos, respecto del alto de fila, de dos opciones:
1-Alto de fila: equivalente a hacer clic derecho del ratón. Nos permite sobre las filas seleccionados configurar su alto.
2-Autoajustar alto de fila: que retorna al alto de fila por defecto!!.


En este punto es donde aparece una singularidad del alto de fila autoajustado, y es que al autoajustar, el alto de fila se configura con el alto predefinido!!.

Pero, ¿cuál es ese alto de fila por defecto?, ¿dónde lo puedo configurar?.


Pues no existe una opción como tal que me lo permita.. pero si algún truco que dejará nuestro alto a la medida deseada...
Y todo pasa por modificar la fuente y el tamaño de esta.


Posibilidades.
1- Cambiar el alto por defecto de una hoja:
Para ello basta cambiar el tamaño de la fuente (aumentar o disminuir) para esa hoja, previa selección de toda la hoja.

2- Cambiar el alto por defecto del libro completo:
Iremos a los Estilos de celda en Ficha Inicio > grupo Celdas > desplegable Estilos de celdas > buscar el estilo Normal.

Alto de fila y Ancho de columna


A continuación lo modificaremos desde 'Formato' y en la ventana de Formato de celdas, desde la pestaña Fuente , cambiamos Tamaño y Fuente

Alto de fila y Ancho de columna


3- Cambiar el alto por defecto de cualquier libro:
Accederemos a las Opciones de Excel, desde la ficha Archivo > Menú General > sección Al crear nuevos libros > opción Tamaño y Fuente.

Alto de fila y Ancho de columna



Lo interesante del caso, cambiar alto de fila por defecto, es que dependerá del tipo de fuente y del tamaño que marquemos.. ya que en función a estas características el alto predeterminado será uno u otro.

jueves, 19 de abril de 2018

Filtro Avanzado Registros Únicos

Días atrás un usuario planteaba una cuestión interesante.
Preguntaba por la forma de aplicar un filtro avanzado para obtener registros únicos.
[...]Realice un filtro avanzado en Excel, en donde utilicé criterios de varias columnas, y con valores únicos.
Para comprobar si estaba correcto, concatené las columnas utilizadas para el filtro avanzado, copie y pegué como texto, y le apliqué formato condicional, duplicar valores y me aparecen 5 registros repetidos.[...]


Partiremos de la siguiente 'base de datos':

Filtro Avanzado Registros Únicos



La idea propuesta es obtener un listado de los registros únicos de acuerdo a un 'id' múltiple, que para nuestro ejemplo estará compuesto de los campos Zona+Comercial+Producto.
Es indiferente que apliquemos o no criterios sobre nuestra herramienta: Filtro Avanzado, ya que opera indistintamente como veremos.


Para el primer caso no aplicaremos criterio alguno, solo obtendremos de la totalidad de la base de datos aquellas combinaciones únicas de esos tres campos deseados: Zona+Comercial+Producto.

Así pues preparamos el destino de nuestro listado, copiando y pegando esos tres encabezados:

Filtro Avanzado Registros Únicos



Con la hoja preparada seleccionamos la base de datos (basta marcar una celda cualquiera de ella) y accedemos a la ficha Datos > grupo Ordenar y Filtrar > botón Avanzadas...
Es nos abrirá la ventana del Filtro avanzado que configuraremos como sigue:
1-Copiar a otro lugar
2-Rango de la lista: $B$2:$F$22 (esto es, la base de datos con el encabezado incluido!!)
3-Rango de criterios: vacío para este primer ejemplo (es decir, trabajamos sobre la totalidad de la base de datos)
4-Copiar a: $I$2:$K$2 (son los tres campos que componen nuestro id múltiple).
5-Solo registros únicos (marcado).

Filtro Avanzado Registros Únicos



Tras aceptar vemos en nuestro rango destino como se han volcado, para esos tres campos, las combinaciones únicas obtenidas desde la base de datos...

Filtro Avanzado Registros Únicos


Se puede comprobar fácilmente como esas doce combinaciones de tres elementos son las únicas existentes en nuestro origen...

De manera similar podríamos, además, haber aplicado unos criterios de filtro, para obtener las combinaciones únicas de solo aquellos registros que cumplan aquellos criterios...
Veamos la imagen siguiente, donde se especifica un criterio por Zona, y donde queremos listar solo las combinaciones/registros únicos de éstos.
1-Copiar a otro lugar
2-Rango de la lista: $B$2:$F$22 (esto es, la base de datos con el encabezado incluido!!)
3-Rango de criterios: $I$2:$M$3 (donde incorporamos los criterios deseados)
4-Copiar a: $I$7:$K$7 (son los tres campos que componen nuestro id múltiple).
5-Solo registros únicos (marcado).

Filtro Avanzado Registros Únicos



El resultado tras aceptar:

Filtro Avanzado Registros Únicos


Obteniendo el listado de combinaciones únicas que verifican nuestros criterios para esos tres campos Zona+Comercial+Producto.

martes, 17 de abril de 2018

Hora superior a 10.000

Un usuario preguntaba, en un comentario, por la forma de trabajar cuando la hora superara las 10.000
[...]como puedo hacer que se pueda llevar acabo una operación de mas de 10 mil horas?[...]


Es importante conocer nuestra herramienta de trabajo -Excel-, y sus limitaciones.
En concreto el que afecta al:
Período de tiempo máximo que puede escribirse:= 9999:59:59

Puedes ver algunas más aquí o aquí.


Por tanto la hora máxima que se puede escribir son las 9999:59:59.
Es importante subrayar la palabra 'escribir'.. ya que en realidad a través de operaciones o fórmulas podremos trabajar y reconocer como 'hora máxima' las:
71003183:59:59
hora que equivale a la fecha máxima reconocida por Excel:
31/12/9999 23:59:59


Y en esta parte es donde reside la solución para trabajar o escribir una hora superior a la reconocida (9999:59:59), será a través de cálculos.

Veamos un ejemplo, donde sumé varias celdas con horas, que en total exceden del límite de las 10000 horas. Como se ve en la imagen se suma correctamente y se devuelve el dato correcto:

Hora superior a 10.000



En eso consistirá nuestro trabajo, en operar sobre la hora a escribir, para obtenerla a partir de un cálculo, y luego sencillamente aplicarle un formato tipo: [h]:mm:ss.

De hecho, en una celda podríamos escribir:
=10000/24+1/24/60+1/24/60/60
y tras aplicarle el formato indicado, veríamos la hora:
10000:01:01


Extrapolamos ese cálculo, y creamos una UDF que trabajará de forma parecida a la función
NSHORA
o la función
FECHA

Así pues, en un módulo estándar del libro incluimos el siguiente procedimiento Function:

Function Horas10000(hora As Double, _
                    minunto As Double, _
                    segundo As Double) As Double
                        
Dim hr As Double, min As Double, sec As Double
'convertimos a decimal las horas, minutos y segundos...
'dividimos por 24 por que tomamos como base el formato de [h]:mm:ss
'que permite incrementar el número de horas por días completos
If hora >= 24 Then
    hr = hora / 24
    min = (minunto / 24) / 60
    seg = ((segundo / 24) / 60) / 60
Else
    'por si acaso el número de hors total no excede de las 24 horas...
    hr = hora
    min = minunto / 60
    seg = (segundo / 60) / 60
End If
'y finalmente devolvemos a la celda la suma
'que corresponderá con el valor buscado...
Horas10000 = hr + min + seg
End Function



Podemos comprobar como introduciendo en una celda, por ejemplo, B8 la fórmula:
=Horas10000(10000;1;1)
obtenemos la hora buscada:
10000:01:01

Solución encontrada...

jueves, 12 de abril de 2018

Personalizar la barra de acceso rápido para un libro en particular

Hace algún tiempo escribía sobre la forma de trabajar con la barra de herramientas de acceso rápido (ver).
En esa entrada veíamos la manera de exportar o importar nuestra configuración personalizada...

Y es que existe una idea generalizada que esa personalización de la barra de herramientas de acceso rápido es igual para cualquier libro de Excel que abramos con nuestro equipo.

Hoy veremos que esto no es del todo cierto, y que si lo consideramos, podemos personalizar nuestra barra para un libro de Excel en particular.


Lo primero que debemos hacer es acceder a la opción de Excel: Personalizar barra de herramientas de acceso rápido.
Hay varias formas, la más simple es hacer clic derecho sobre la cinta de opciones y luego seleccionar la opción buscada.

Personalizar la barra de acceso rápido para un libro en particular



Una vez en la ventana de opciones de Excel añadiríamos los botones deseados para personalizar nuestro libro. Basta buscarlos en la parte izquierda...
OJO!, importante, antes de hacer doble clic o presionar Agregar, tenemos que cambiar el desplegable de arriba a la derecha y elegir la opción:
Para 'Nombre_de_nuestro_libro'

Solo una vez desplegado podremos incorporar nuevos botones a nuestra barra personalizada...

Por ejemplo, en mi caso solo añadiré el botón de Actualizar todo.

Personalizar la barra de acceso rápido para un libro en particular



Una vez guardado el libro, y la próxima vez que lo abramos, veremos nuestra barra de herramientas de acceso rápido personalizada.

IMPORTANTE!!
Lo que veremos para ese libro es primero todos los botones de nuestra 'configuración general', y al final, a la derecha de la barra, los botones añadidos en particular para nuestro libro!.

martes, 10 de abril de 2018

VBA: Contar días alternos transcurridos

Días atrás un usuario planteaba una cuestión interesante a través de un comentario.
Preguntaba por la forma de obtener un día final considerando solo ciertos días hábiles de la semana.
[...]Como puedo conocer la fecha final , a partir de una fecha inicial , con un número de días?
Pero sólo quiero contar los días lunes, miércoles y viernes. Ejemplo: hoy tengo un inventario de 10 pastillas de un medicamento. Tengo que tomarme una sola pastilla por día. Pero sólo me la tomo los lunes, miércoles y viernes. Por lo tanto tengo un inventario de 10 días de medicamentos. Pero no son continuos . Ya q la tomo son los lunes, miércoles y viernes.
Como hago para saber hasta qué fecha tengo pastillas ?[...]


La idea está bien expresada por el lector, a partir de una fecha dada, por ejemplo 3 de enero de 2018, si contamos 10 días teniendo en cuenta solo Lunes, Miércoles y Viernes, cuál sería el último día en que finalizaría ??.
Esto es, cuál es la fecha final teniendo en cuenta ciertos días hábiles dentro de la semana.

VBA: Contar días alternos transcurridos



En la imagen he coloreado en amarillo los diez días habilitados...
Nuestra fórmula incluida en la celda C10 es:
=DiasAlternos(B10;10;1;0;1;0;1;0;0)

que como se observa tiene declarada como primer argumento argumento (Fecha de partida) la celda B10.
El segundo argumento el número de días hábiles a considerar (en el ejemplo 10).
Y los siguientes siete argumentos permiten VERDADERO y FALSO (1 y 0) para indicar cuáles son esos días hábiles; para el ejemplo lunes, miércoles y viernes...


Generaremos una función personalizada con algo de código simple.

En un módulo estándar del libro incluimos el siguiente procedimiento:

Function DiasAlternos(FechaInicial As Date, NumDias As Long, _
                        Optional lun As Boolean = True, _
                        Optional mar As Boolean = True, _
                        Optional mie As Boolean = True, _
                        Optional jue As Boolean = True, _
                        Optional vie As Boolean = True, _
                        Optional sab As Boolean = True, _
                        Optional dom As Boolean = True) As Date
'la función opera con dos argumentos obligatorios
'FechaInicial que será la fecha de partida
'NumDias que es el número de días a incrementar

'con siete argumentos opcionales
'con valor predeterminado de VERDADERO
'indicaremos 0 ó FALSO si no queremos considerarlo en el conteo
'indicaremos 1 ó VERDADERO si sí queremos considerarlo en el conteo

'definimos las variables a usar
Dim FechaFinal As Date, contador As Long
contador = 0

'recorremos una a una las fechas desde la Fecha de partida
'hasta
For fecha = (FechaInicial) To ((FechaInicial + NumDias * 7))
    'mantenemos el recorrido mientras no lleguemos al límite de días estipuladdo en la función
    If contador < NumDias Then
        'incrementamos la fecha según las elección del usuario
        'indicada en los siete argumentos
        If Weekday(fecha, vbMonday) = 1 And lun Then
            FechaFinal = fecha
            contador = contador + 1
        ElseIf Weekday(fecha, vbMonday) = 2 And mar Then
            FechaFinal = fecha
            contador = contador + 1
        ElseIf Weekday(fecha, vbMonday) = 3 And mie Then
            FechaFinal = fecha
            contador = contador + 1
        ElseIf Weekday(fecha, vbMonday) = 4 And jue Then
            FechaFinal = fecha
            contador = contador + 1
        ElseIf Weekday(fecha, vbMonday) = 5 And vie Then
            FechaFinal = fecha
            contador = contador + 1
        ElseIf Weekday(fecha, vbMonday) = 6 And sab Then
            FechaFinal = fecha
            contador = contador + 1
        ElseIf Weekday(fecha, vbMonday) = 7 And dom Then
            FechaFinal = fecha
            contador = contador + 1
        End If
    End If
Next fecha
'finalmente devolvemos a la función el valor de la fecha...
DiasAlternos = FechaFinal
                       
End Function

Como podemos comprobar el resultado es el esperado...

jueves, 5 de abril de 2018

Crear Relaciones para comparar listados

Una posibilidad que nos ofrece el complemento Power Pivot es la de crear relaciones entre tablas, lo que nos habilita un mundo de posibilidades para cruzar información entre diferentes orígenes.
En el caso del día cruzaremos información de dos tablas para descubrir coincidencias entre ambas.


Nuestras dos tablas llamadas 'TblStock' y 'TblPrecios':

Crear Relaciones para comparar listados



Si observamos el listado de la tabla 'TblStock' veremos que como elementos únicos tenemos:
a01, a02, a03, a04, a06 y a07
Mientras que en la tabla 'TblPrecios' tenemos:
a01, a02, a03, a04, a05, y a08

Esto significa que la coincidencia de códigos en la TblPrecios respecto de la TblStock es de cuatro elementos:
a01, a02, a03 y a04


Veamos cómo controlar estas coincidencias.

En primer lugar accederemos a la Creación de relaciones desde la Ficha Datos > grupo Herramientas de datos > botón Relaciones

Crear Relaciones para comparar listados


Es interesante generar la relación desde este botón ya que nos evita acceder al complemento Power Pivot... lo que normalmente ralentiza el proceso.

Al entrar en la herramienta, automáticamente detecta las tablas existentes, y nos habilita para definir la relación entre nuestras tablas... Para nuestro ejemplo crearemos una Nueva relación de:
TblStock - campo Referencia
a
TblPrecios - campo Código

Crear Relaciones para comparar listados



Con la relación creada ya podemos generar nuestra tabla dinámica.
Navegamos a la Ficha Insertar > grupo Tablas > tabla dinámica y en la ventana del asistente seleccionamos la opción:
Usar el modelo de datos de este libro

Crear Relaciones para comparar listados



Solo nos queda componer la tabla dinámica, para lo que arrastramos el campo 'Referencias' al área de filas, igualmente el campo 'Código' al área de filas, y el campo 'Referencias' al área de valores resumido por recuento.

Crear Relaciones para comparar listados



La lectura del resultado mostrado en la tabla dinámica debe hacerse con la intención de encontrar coincidencias de la 'TblStock' con la 'TblPrecios' en ese sentido...

martes, 3 de abril de 2018

Resumir valores como Recuento distinto en tablas dinámicas

Combinaremos en el día de hoy una herramienta de tabla dinámica especial cuando viene del complemento Power Pivot: el Recuento distinto.

La idea viene por la necesidad de contabilizar dentro de una agrupación el número de elementos distintos que corresponden.


Comenzamos a partir de la siguiente tabla de pedidos:

Resumir valores como Recuento distinto en tablas dinámicas



En este sencillo listado se comprueba fácilmente como en:
* enero existen solo dos 'códigos' distintos (a01 y a06)
* en febrero solo cuatro 'códigos' distintos (a01, a03, a05 y a07)
* y en marzo solo tres 'códigos' distintos (a02, a04 y a06)

pues ese es nuestro objetivo precisamente, que nuestra tabla dinámica devuelva ese dato.


Para ello, y a partir de nuestra tabla (que he llamado 'TblPedidos'), creamos una tabla dinámica. Por ejemplo desde la Ficha Insertar > grupo Tablas > Insertar Tabla dinámica.

Cuando se abra el asistente tendremos especial cuidado de seleccionar la opción:
Agregar estos datos al modelo de datos

Resumir valores como Recuento distinto en tablas dinámicas


Insertamos la tabla dinámica donde deseemos (en una nueva hoja o una ubicación concreta ya existente).
Yo he elegido crearla para el ejemplo a la derecha de la Tabla 'TblPedidos' en la misma hoja.


Configuramos el aspecto de la tabla respecto a campo...
Para lo cual arrastro el campo Fechas al área de filas;
el campo Importe al área de valores;
y el campo Código también al área de valores.

Sobre este campo 'Código' accederemos a la configuración de campo de valor.. basta presionar clic derecho y buscar esta opción, y en la pestaña de Resumir valores por, al final de las opciones de cálculo, encontraremos la deseada: Recuento distinto

Resumir valores como Recuento distinto en tablas dinámicas


Tras aceptar comprobamos que el dato mostrado era precisamente el cálculo que necesitábamos.