Создайте гистограмму из двух массивов

#python #list #numpy #nested-lists

Вопрос:

У меня есть два массива numpy с одинаковыми размерами: весами и процентами. Проценты-это «реальные» данные, а веса-это количество каждых «реальных» данных в гистограмме.

Например)

 weights = [[0, 1, 1, 4, 2]  [0, 1, 0, 3, 5]] percents = [[1, 2, 3, 4, 5]  [1, 2, 3, 4, 5]]  

(каждая строка процентов одинакова)

Я хотел бы «умножить» их вместе таким образом, чтобы получить веса[x] * [проценты[x]]:

 results = [[0 * [1]   1 * [2]   1 * [3]   4 * [4]   2 * [5]  [0 * [1]   1 * [2]   0 * [3]   3 * [4]   5 * [5]]  = [[2, 3, 4, 4, 4, 4, 5, 5]  [2, 4, 4, 4, 5, 5, 5, 5, 5]]  

Обратите внимание, что длина каждой строки может быть разной.. В идеале это можно сделать в numpy, но из-за этого он может превратиться в список списков.

Редактировать: Мне удалось собрать эти вложенные циклы для, но, очевидно, это не идеально:

 list_of_hists = [] for index in df.index:  hist = []  # Create a list of lists, later to be flattened to 'results'  for i, percent in enumerate(percents):  hist.append(  # For each percent, create a list of [percent] * weight  [percent]  * int(  df.iloc[index].values[i]  )  )  # flatten the list of lists in hist  results = [val for list_ in hist for val in list_]  list_of_hists.append(results)  

Комментарии:

1. На самом деле вам не нужно зацикливаться. Но поскольку длина массивов ваших входных данных несбалансирована, что-то вроде np.split может быть хорошим выбором.

Ответ №1:

Существует np.repeat устройство, предназначенное для такого рода операций, но оно не работает в 2D-случае. Поэтому вместо этого вам нужно работать с плоскими представлениями массивов.

 weights = np.array([[0, 1, 1, 4, 2], [0, 1, 0, 3, 5]]) percents = np.array([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]) gt;gt;gt; np.repeat(percents.ravel(), weights.ravel()) array([2, 3, 4, 4, 4, 4, 5, 5, 2, 4, 4, 4, 5, 5, 5, 5, 5])  

И после этого вам нужно выбрать места для индекса, где его разделить:

 gt;gt;gt; np.split(np.repeat(percents.ravel(), weights.ravel()), np.cumsum(np.sum(weights, axis=1)[:-1])) [array([2, 3, 4, 4, 4, 4, 5, 5]), array([2, 4, 4, 4, 5, 5, 5, 5, 5])]  

Обратите внимание, что np.split это довольно неэффективная операция, а также ваше желание сделать массив из строк неравной длины.

Комментарии:

1. Это тоже разумное решение, спасибо!

Ответ №2:

Вы можете использовать понимание списка и reduce из functools :

 import functools res=[functools.reduce(lambda x,y: x y,  [x*[y] for x, y in zip(w, p)])  for w, p in zip(weights, percents)]  

выход:

 [[2, 3, 4, 4, 4, 4, 5, 5],  [2, 4, 4, 4, 5, 5, 5, 5, 5]]  

Или просто решение только для понимания списка:

 res= [[j for i in [x*[y]  for x, y in zip(w, p)]  for j in i]  for w, p in zip(weights, percents)]  

выход:

 [[2, 3, 4, 4, 4, 4, 5, 5],  [2, 4, 4, 4, 5, 5, 5, 5, 5]]  

Комментарии:

1. Это здорово, большое вам спасибо!