Saltar al contenido

¿Construir un cubo básico con numpy?

Hacemos una verificación profunda cada sección de nuestra página web con la meta de mostrarte siempre la información más veraz y actual.

Solución:

creo numpymatrices de registros se puede utilizar para esta tarea, a continuación se muestra mi solución basada en matrices de registros.

class rec_array():
    
    def __init__(self,author=None,book=None,year=None,sales=None):
        self.dtype = [('author','

Basado en esto rec_array, dados los datos

author = 4*["Shakespeare"]+ 2*["Dante"]
book = 2*["Hamlet"] + 2*["Romeo"] + 2*["Inferno"]
year = 3*["2000", "2001"]
sales = [104.2, 99.0, 27.0, 19.0, 11.6, 12.6]

creamos una instancia

test = rec_array()
test.add_record(author,book,year,sales)

Si, por ejemplo, desea las ventas del Romeo de Shakespeare, simplemente puede hacer esto

test.get_view([["author","==","Shakespeare"],["book","==","Romeo"]])

la salida es 46.0

o, también puedes hacer

test.get_view([["author","==","Shakespeare"],["year","<=","2000"]])

la salida es 131,2

Para la estructura de datos, podría definir la siguiente clase:

class Cube:

    def __init__(self, row_index, col_index, data):
        self.row_index = r: i for i, r in enumerate(row_index)
        self.col_index = c: i for i, c in enumerate(col_index)
        self.data = data

    def __getitem__(self, item):
        row, col = item
        return self.data[self.row_index[row] , self.col_index[col]]

    def __repr__(self):
        return repr(self.data)

Básicamente, una envoltura ligera alrededor de un numpy bidimensional. array. Para calcular la tabulación cruzada, puede hacer algo como esto:

def _x_tab(rows, columns, values):
    """Function for computing the cross-tab of simple arrays"""
    unique_values_all_cols, idx = zip(*(np.unique(col, return_inverse=True) for col in [rows, columns]))

    shape_xt = [uniq_vals_col.size for uniq_vals_col in unique_values_all_cols]

    xt = np.zeros(shape_xt, dtype=np.float)
    np.add.at(xt, idx, values)

    return unique_values_all_cols, xt


def make_index(a, r):
    """Make array of tuples"""
    l = [tuple(row) for row in a[:, r]]
    return make_object_array(l)


def make_object_array(l):
    a = np.empty(len(l), dtype=object)
    a[:] = l
    return a


def fill_label(ar, le):
    """Fill missing parts with ALL label"""
    missing = tuple(["ALL"] * le)
    return [(e + missing)[:le] for e in ar]

def x_tab(rows, cols, values):
    """Main function for cross tabulation"""
    _, l_cols = rows.shape

    total_agg = []
    total_idx = []
    for i in range(l_cols + 1):
        (idx, _), agg = _x_tab(make_index(rows, list(range(i))), cols, values)
        total_idx.extend(fill_label(idx, l_cols))
        total_agg.append(agg)

    stacked_agg = np.vstack(total_agg)
    stacked_agg_total = stacked_agg.sum(axis=1).reshape(-1, 1)

    return Cube(total_idx, list(dict.fromkeys(cols)), np.concatenate((stacked_agg, stacked_agg_total), axis=1))

Suponga como entrada un arr array:

[['Shakespeare' 'Hamlet' 2000 104.2]
 ['Shakespeare' 'Hamlet' 2001 99.0]
 ['Shakespeare' 'Romeo' 2000 27.0]
 ['Shakespeare' 'Romeo' 2001 19.0]
 ['Dante' 'Inferno' 2000 11.6]
 ['Dante' 'Inferno' 2001 12.6]]

Luego x_tab se puede llamar así:

result = x_tab(arr[:, [0, 1]], arr[:, 2], arr[:, 3])
print(result)

Producción

array([[142.8, 130.6, 273.4],
       [ 11.6,  12.6,  24.2],
       [131.2, 118. , 249.2],
       [ 11.6,  12.6,  24.2],
       [104.2,  99. , 203.2],
       [ 27. ,  19. ,  46. ]])

Tenga en cuenta que esta representación (repr) es solo con el propósito de mostrar los resultados, puede cambiarla cuando lo crea conveniente. Luego puede acceder a las celdas del cubo de la siguiente manera:

print(result[('Dante', 'ALL'), 2001])
print(result[('Dante', 'Inferno'), 2001])
print(result[('Shakespeare', 'Hamlet'), 2000])

Producción

12.6
12.6
104.2

Tenga en cuenta que la mayor parte de las operaciones se encuentran en la función _x_tab, que utiliza funciones numéricas puras. Al mismo tiempo, proporciona una interfaz flexible para cualquier función de agregación que elija, simplemente cambie ufunc en esta línea:

np.add.at(xt, idx, values)

por cualquier otro de esta lista. Para obtener más información, consulte la documentación sobre el operador at.

Puede encontrar una copia de trabajo del código aquí. Lo anterior se basa en esta esencia.

Nota
Esto supone que está pasando varias columnas para el índice (parámetro de filas).

Aquí hay un boceto de una solución, obviamente, incluiría funciones y clases auxiliares para proporcionar una interfaz fácil. La idea es asignar cada nombre único a un índice (secuencial aquí para simplificar) y luego usarlo como índice para almacenar el valor en un array. Es subóptimo en el sentido de que debe rellenar un array al tamaño máximo de la mayor cantidad de elementos diferentes. los array es ceros de lo contrario, así que no se incluya en las sumas. Puede considerar las matrices de máscaras y la suma de máscaras si desea evitar agregar elementos cero.

import numpy as np

def get_dict(x):
    return a:i for i, a in enumerate(set(x))

#Mapping name to unique contiguous numbers (obviously put in a fn or class)
author = 4*["Shakespeare"]+ 2*["Dante"]
book = 2*["Hamlet"] + 2*["Romeo"] + 2*["Inferno"]
year = 3*["2000", "2001"]
sales = [104.2, 99.0, 27.0, 19.0, 11.6, 12.6]

#Define dictonary of indices
d = get_dict(author)
d.update(get_dict(book))
d.update(get_dict(year)) 

#Index values to put in multi-dimension array
ai = [d[i] for i in author]
bi = [d[i] for i in book]
yi = [d[i] for i in year]

#Pad array up to maximum size
A = np.zeros([np.max(ai)+1, np.max(bi)+1, np.max(yi)+1])

#Store elements with unique name as index in 3D datacube
for n in range(len(sales)):
    i = ai[n]; j = bi[n]; k = yi[n]
    A[i,j,k] = sales[n]

#Now we can get the various sums, for example all sales
print("Total=", np.sum(A))

#All shakespeare (0)
print("All shakespeare=", np.sum(A[d["Shakespeare"],:,:]))

#All year 2001
print("All year 2001", np.sum(A[:,:,d["2001"]]))

#All Shakespeare in 2000
print("All Shakespeare in 2000", np.sum(A[d["Shakespeare"],:,d["2000"]]))

Reseñas y calificaciones

Acuérdate de que tienes autorización de decir si diste con la respuesta.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *