2016-03-01 3 views
2

У меня есть изображение в Numpy массива X:Заменить значения группы с группой в совокупности Numpy/панде

array([[ 0.01176471, 0.49019608, 0.01568627], 
     [ 0.01176471, 0.49019608, 0.01568627], 
     [ 0.00784314, 0.49411765, 0.00784314], 
     ..., 
     [ 0.03921569, 0.08235294, 0.10588235], 
     [ 0.09411765, 0.14901961, 0.18431373], 
     [ 0.10196078, 0.15294118, 0.21568627]]) 

Я побежал алгоритм clusterizer над этим массивом, чтобы найти похожие цвета и иметь другой массив с классами для каждого пиксель Y:

array([19, 19, 19, ..., 37, 20, 20], dtype=int32) 

Каких самые быстрые, хорошенький, и большинство pythonistic способов заменить цвет всех пикселей в кластере с среднем по этой группе?

Я придумал следующий код:

import pandas as pd 
import numpy as np 
<...> 
df = pd.DataFrame.from_records(X, columns=list('rgb')) 
df['cls'] = Y 
mean_colors = df.groupby('cls').mean().values 
# as suggested in comments below 
# for cls in range(len(mean_colors)): 
# X[Y==cls] = mean_colors[cls] 
X = mean_colors[Y] 

Есть ли способ сделать это только в панд или только в NumPy?

+0

Предполагая, что 'Y' содержит все метки, как насчет простой индексации' mean_colors [Y] '? – Divakar

+0

Для вашего примера ваш код не работает, потому что у вас есть «Y» 3 разных значения, и когда вы сравниваете «Y == cls», ничего не происходит, потому что в индексе нет ... (cls только равен 0 , 1, 2) –

+0

@ Дивакар да, это красиво, спасибо! – Direvius

ответ

1

Предполагая, что все метки присутствуют в Y, вы можете использовать basic-indexing -

mean_colors[Y] 

В тех случаях, когда индексации в то же место несколько раз, для выполнения вы можете также использовать np.take вместо чистого индексации, как так -

np.take(mean_colors,Y,axis=0) 

время выполнения теста -

In [107]: X = np.random.rand(10000,3) 

In [108]: Y = np.random.randint(0,100,(10000)) 

In [109]: np.allclose(np.take(mean_colors,Y,axis=0),mean_colors[Y]) 
Out[109]: True   # Verify approaches 

In [110]: %timeit mean_colors[Y] 
1000 loops, best of 3: 280 µs per loop 

In [111]: %timeit np.take(mean_colors,Y,axis=0) 
10000 loops, best of 3: 63.7 µs per loop 
+1

На моей машине с моими данными: чистое индексирование составляет 6,13 мс, занимает 2,08 мс и 'df.groupby ('cls'). Transform (np .mean) .values' составляет 65,2 мс. Я думаю, что эти два являются лучшими =) – Direvius

+0

ах, я не считал, что мне нужно найти mean_colors до – Direvius

+1

чистое индексирование: 610 мс; произвести индексацию: 604 мс; pandas transform: 659 мс – Direvius

1

Вы можете использовать transform для объекта GroupBy, а затем присвоить .values результат вашего X:

X = df.groupby('cls').transform(np.mean).values 

Информация о tranfrom от help:

transform(func, *args, **kwargs) method of pandas.core.groupby.DataFrameGroupBy instance 
    Call function producing a like-indexed DataFrame on each group and 
    return a DataFrame having the same indexes as the original object 
    filled with the transformed values 

    Parameters 
    ---------- 
    f : function 
     Function to apply to each subframe 

    Notes 
    ----- 
    Each subframe is endowed the attribute 'name' in case you need to know 
    which group you are working on. 

    Examples 
    -------- 
    >>> grouped = df.groupby(lambda x: mapping[x]) 
    >>> grouped.transform(lambda x: (x - x.mean())/x.std()) 
Смежные вопросы