Как выполнить векторизацию биннинга, используя только панд - PullRequest
0 голосов
/ 29 августа 2018

Я пытаюсь найти правильный синтаксис для выбора фрагмента строк в кадре данных Pandas, условного для многомерного фрагмента.

Я хочу выполнить разбивку по гистограмме, предоставляя ячейки в многомерном массиве NumPy и сравнивая векторно, помещается ли запись в одну ячейку или другую. Результатом должен быть одномерный массив с числом элементов в каждой корзине.

Моя первоначальная попытка модели приведена ниже для справки, хотя с тех пор я предоставил частичную реализацию (вместо этого используя цикл) в ответе ниже:

import numpy as np
import pandas as pd

## Generate Random Data
X = np.random.normal(0.5,0.1,100)

## Populate a Pandas DataFrame
DF = pd.DataFrame({'x':X})

## Some example, hardcoded 1D bins. 
bins = np.array([
                [[0.0,0.2]],
                [[0.2,0.4]],
                [[0.4,0.6]],
                [[0.6,0.8]],
                [[0.8,1.0]]
                ])

hist = np.zeros(shape=(4,))
hist[:] = np.sum(
                 DF.loc[   (DF >= bins[:,:,0]) &
                           (DF > bins[:,:,1])
                        ].dropna(how='all')
                 )

Как правило, данные являются n-мерными, а ячейки следуют указанному выше шаблону:

[[x_min, x_max], [y_min, ymax], [z_min, z_max]] 

для каждого бина (отсюда очевидный «дополнительный» слой вложения в 1D примере выше). Поэтому нарезка должна работать для DataFrames нескольких столбцов, так что

DF['x'] >= x_min and DF['x'] < x_max and 
DF['y'] >= y_min and DF['y'] < y_max

и т.д.. и, следовательно, должен быть независимым от измерений; подход среза представляется наиболее естественным способом достижения этого и должен быть вычислительно более эффективным, если это возможно.

Если нет, то в моём ответе можно было бы применить подход к пониманию списка, но у меня были проблемы с многомерностью.

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

Как уже упоминалось в моем комментарии к ответу SpghttCd, я нашел рабочий подход, который использует понимание списка вместо среза при заполнении гистограммы. Похоже, что он точно рассчитывает количество записей в каждой корзине (проверено в 1D и 2D), но не элегантен, и я был бы благодарен за улучшения для людей, более близко знакомых с библиотекой панд. Возможно, он выглядит немного странным из-за целочисленного округления.

Я представляю код ниже, с примером выше, расширенным до 2D.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.patches as patches

## Generate Random Data
X = np.random.normal(0.5,0.1,150)
Y = np.random.normal(0.5,0.2,150)

## Populate a Pandas DataFrame
DF = pd.DataFrame({'x':X,'y':Y})

## Some example, hardcoded 2D bins. 
bins = np.array([
            [[0.0,0.2],[0.0,1.5]],
            [[0.2,0.4],[0.0,1.5]],
            [[0.4,0.6],[0.0,1.5]],
            [[0.6,0.8],[0.0,1.5]],
            [[0.8,1.0],[0.0,1.5]]
            ])


hist = np.array([  
                np.product(  
                          np.sum(     (DF.iloc[:,:] >= bins[:,:,0][i][:]) & 
                                      (DF.iloc[:,:] <  bins[:,:,1][i][:])
                          ))/len(DF) 
                 for i in range(len(bins)) ], dtype=np.int32)[:,0]


print(hist)    
print(sum(hist))

## 2D Plot
plt.style.use('seaborn')
fig, axes = plt.subplots(figsize=(4, 3.5))
plt.scatter(DF['x'],DF['y'], 5, 'k')
axes.set_xlabel('x')
axes.set_xlabel('y')
axes.set_xlim(-0.5,1.5)
axes.set_ylim(-0.5,2)

# Create a Rectangle patch for each bin and plot
for i,bin in enumerate(bins):

    rect = patches.Rectangle(   (bin[0][0],bin[1][0]),
                                bin[0][1]-bin[0][0],
                                bin[1][1]-bin[1][0],
                                linewidth=1,
                                edgecolor='r',facecolor='none')
    # Add the patch to the Axes
    axes.add_patch(rect)

plt.show()

Это часть личного проекта по переизобретению N-мерных гистограмм в Python со ссылкой на обсуждение в этом вопросе SciComp .

0 голосов
/ 29 августа 2018

Я не уверен, действительно ли вам нужны панды, но numpy имеет многомерную функцию гистограммы, которая называется histogramdd.

Вот тестовый цикл, который генерирует три массива с увеличивающимся числом столбцов, все 100 строк в длину и соответствующие бинарные массивы, все с границами вашего образца сверху.

Просто посмотрите, если это то, что вы искали:

for i in range(1, 4):
    data = np.random.random([100, i])
    bins = np.linspace(0, 1, 6)
    bins = [bins for _ in range(i)]
    print('shape of data: ', np.shape(data))
    print('bin borders: ',bins)
    print('\nresult: ', np.histogramdd(data, bins), '\n\n')

результат:

shape of data:  (100, 1)
bin borders:  [array([ 0. ,  0.2,  0.4,  0.6,  0.8,  1. ])]

result:  (array([ 14.,  26.,  21.,  24.,  15.]), [array([ 0. ,  0.2,  0.4,  0.6,  0.8,  1. ])]) 


shape of data:  (100, 2)
bin borders:  [array([ 0. ,  0.2,  0.4,  0.6,  0.8,  1. ]), array([ 0. ,  0.2,  0.4,  0.6,  0.8,  1. ])]

result:  (array([[  5.,   7.,   5.,   2.,   3.],
       [  5.,   4.,   5.,   3.,   1.],
       [  5.,   3.,   7.,   1.,   3.],
       [  2.,   6.,   4.,   3.,   7.],
       [  1.,  11.,   3.,   2.,   2.]]), [array([ 0. ,  0.2,  0.4,  0.6,  0.8,  1. ]), array([ 0. ,  0.2,  0.4,  0.6,  0.8,  1. ])]) 


shape of data:  (100, 3)
bin borders:  [array([ 0. ,  0.2,  0.4,  0.6,  0.8,  1. ]), array([ 0. ,  0.2,  0.4,  0.6,  0.8,  1. ]), array([ 0. ,  0.2,  0.4,  0.6,  0.8,  1. ])]

result:  (array([[[ 1.,  0.,  0.,  0.,  2.],
        [ 0.,  1.,  1.,  1.,  0.],
        [ 0.,  1.,  1.,  2.,  1.],
        [ 2.,  2.,  0.,  2.,  0.],
        [ 1.,  1.,  1.,  2.,  1.]],

       [[ 2.,  0.,  1.,  1.,  1.],
        [ 0.,  0.,  0.,  1.,  0.],
        [ 1.,  2.,  2.,  0.,  1.],
        [ 0.,  1.,  1.,  2.,  0.],
        [ 0.,  0.,  1.,  1.,  0.]],

       [[ 1.,  0.,  0.,  0.,  1.],
        [ 1.,  0.,  2.,  0.,  4.],
        [ 0.,  1.,  0.,  1.,  1.],
        [ 2.,  0.,  0.,  0.,  0.],
        [ 1.,  1.,  0.,  1.,  0.]],

       [[ 1.,  2.,  1.,  1.,  0.],
        [ 0.,  1.,  1.,  0.,  2.],
        [ 2.,  1.,  1.,  0.,  1.],
        [ 2.,  0.,  1.,  1.,  0.],
        [ 0.,  2.,  0.,  2.,  1.]],

       [[ 1.,  3.,  0.,  1.,  0.],
        [ 1.,  1.,  0.,  0.,  0.],
        [ 1.,  1.,  0.,  0.,  0.],
        [ 1.,  1.,  2.,  1.,  1.],
        [ 1.,  1.,  1.,  0.,  1.]]]), [array([ 0. ,  0.2,  0.4,  0.6,  0.8,  1. ]), array([ 0. ,  0.2,  0.4,  0.6,  0.8,  1. ]), array([ 0. ,  0.2,  0.4,  0.6,  0.8,  1. ])])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...