Tengo un pd. Serie de flotadores y me gustaría agruparlo en n contenedores donde el tamaño del contenedor para cada contenedor está configurado de modo que max / min sea un valor predeterminado (por ejemplo, 1.20)?

El requisito significa que el tamaño de los contenedores no es constante. Por ejemplo:

data = pd.Series(np.arange(1, 11.0))
print(data)

0     1.0
1     2.0
2     3.0
3     4.0
4     5.0
5     6.0
6     7.0
7     8.0
8     9.0
9    10.0
dtype: float64

Me gustaría que los tamaños de los contenedores sean:

1.00 <= bin 1 < 1.20
1.20 <= bin 2 < 1.20 x 1.20 = 1.44
1.44 <= bin 3 < 1.44 x 1.20 = 1.73
...

Etcetera

Gracias

3
user13578 7 oct. 2019 a las 16:26

3 respuestas

La mejor respuesta

Gracias a todos por todas las sugerencias. Ninguno hace exactamente lo que buscaba (probablemente porque mi pregunta original no era lo suficientemente clara) pero realmente me ayudaron a descubrir qué hacer, así que decidí publicar mi propia respuesta (espero que esto sea lo que se supone que debo hacer como Soy relativamente nuevo en ser un miembro activo de stackoverflow ...)

Me gustó más la sugerencia vectorizada de @ yatu porque se escalará mejor con conjuntos de datos grandes, pero busco los medios no solo para calcular automáticamente los contenedores, sino también para determinar el número mínimo de contenedores necesarios para cubrir el conjunto de datos.

Este es mi algoritmo propuesto:

  1. El tamaño del contenedor se define de modo que bin_max_i / bin_min_i sea constante:
bin_max_i / bin_min_i = bin_ratio
  1. Calcule el número de contenedores para el tamaño de contenedor requerido (bin_ratio):
data_ratio = data_max / data_min
n_bins = math.ceil( math.log(data_ratio) / math.log(bin_ratio) )
  1. Establezca el límite inferior para el contenedor más pequeño para que el punto de datos más pequeño quepa en él:
bin_min_0 = data_min
  1. Cree n contenedores no superpuestos que cumplan las condiciones:
bin_min_i+1 = bin_max_i
bin_max_i+1 = bin_min_i+1 * bin_ratio
  1. Deje de crear más contenedores una vez que todo el conjunto de datos se pueda dividir entre los contenedores ya creados. En otras palabras, pare una vez:
bin_max_last > data_max

Aquí hay un fragmento de código:

import math
import pandas as pd

bin_ratio = 1.20

data = pd.Series(np.arange(2,12))
data_ratio = max(data) / min(data)

n_bins = math.ceil( math.log(data_ratio) / math.log(bin_ratio) )
n_bins = n_bins + 1               # bin ranges are defined as [min, max)

bins = np.full(n_bins, bin_ratio) # initialise the ratios for the bins limits
bins[0] = bin_min_0               # initialise the lower limit for the 1st bin
bins = np.cumprod(bins)           # generate bins

print(bins)
[ 2.          2.4         2.88        3.456       4.1472      4.97664
  5.971968    7.1663616   8.59963392 10.3195607  12.38347284]

Ahora estoy listo para construir un histograma de los datos:

data.hist(bins=bins)
0
user13578 8 oct. 2019 a las 08:49

Creo que esta es la mejor manera de hacerlo porque está considerando los valores max y min de su matriz. Por lo tanto, no tendrá que preocuparse por los valores que está utilizando, solo el multiplicador o step_size para sus contenedores (por supuesto, deberá agregar un nombre de columna o alguna información adicional si va a trabajando con un DataFrame):

data = pd.Series(np.arange(1, 11.0))
bins = []
i = min(data)
while i < max(data):
    bins.append(i)
    i = i*1.2
    bins.append(i)
bins = list(set(bins))
bins.sort()
df = pd.cut(data,bins,include_lowest=True)
print(df)

Salida:

0       (0.999, 1.2]
1     (1.728, 2.074]
2     (2.986, 3.583]
3       (3.583, 4.3]
4        (4.3, 5.16]
5      (5.16, 6.192]
6      (6.192, 7.43]
7      (7.43, 8.916]
8    (8.916, 10.699]
9    (8.916, 10.699]

Salida de contenedores:

Categories (13, interval[float64]): [(0.999, 1.2] < (1.2, 1.44] < (1.44, 1.728] < (1.728, 2.074] < ... <
                                     (5.16, 6.192] < (6.192, 7.43] < (7.43, 8.916] <
                                     (8.916, 10.699]]
0
Celius Stingher 7 oct. 2019 a las 13:49

Aquí hay uno con pd.cut, donde bins se puede calcular tomando el np.cumprod de una matriz llena de 1.2:

data = pd.Series(list(range(11)))
import numpy as np

n = 20 # set accordingly
bins= np.r_[0,np.cumprod(np.full(n, 1.2))]
# array([ 0.        ,  1.2       ,  1.44      ,  1.728 ...
pd.cut(data, bins)

0                 NaN
1          (0.0, 1.2]
2      (1.728, 2.074]
3      (2.986, 3.583]
4        (3.583, 4.3]
5         (4.3, 5.16]
6       (5.16, 6.192]
7       (6.192, 7.43]
8       (7.43, 8.916]
9     (8.916, 10.699]
10    (8.916, 10.699]
dtype: category

Donde los contenedores en este caso suben a:

np.r_[0,np.cumprod(np.full(20, 1.2))]

array([ 0.        ,  1.2       ,  1.44      ,  1.728     ,  2.0736    ,
        2.48832   ,  2.985984  ,  3.5831808 ,  4.29981696,  5.15978035,
        6.19173642,  7.43008371,  8.91610045, 10.69932054, 12.83918465,
       15.40702157, 18.48842589, 22.18611107, 26.62333328, 31.94799994,
       38.33759992])

Entonces tendrá que configurarlo de acuerdo con el rango de valores de los datos reales

0
yatu 7 oct. 2019 a las 13:44
58270531