2016-03-08 1 views
1

Учитывая следующий DataFrame в панд:Как агрегировать значения DataFrame (и быстро выводить массив numpy)?

user item  rating 
1  3  2 
1  4  5 
2  1  5 
3  5  1 
3  1  3 
4  4  4 
4  1  1 
.... 

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

1 2 3 4 5 
1 nan nan 2 5 nan 
2 5 nan nan nan nan 
3 3 nan nan nan 1 
4 1 nan nan 4 nan 

Как использовать функцию apply, чтобы сделать это быстро?

ответ

0

Чтобы сделать это быстро, сделать это с Numpy инструменты:

def pivotarray(df): 
    users,i= np.unique(df['user'],return_inverse=True) 
    item,j= np.unique(df['item'],return_inverse=True) 
    a=zeros((len(users),len(item)),int) 
    a[i,j]=df['rating'] 
    return a 

Тогда (вы можете заполнить с NaN раньше, если необходимое):

In [464]: pivotarray(df) 
Out[464]: 
array([[0, 2, 5, 0], 
     [5, 0, 0, 0], 
     [3, 0, 0, 1], 
     [1, 0, 4, 0]]) 

колонок-не существует, потому что нет ни одного пункта 2.

Gain является младшим:

In [465]: %timeit pivotarray(df) 
1000 loops, best of 3: 417 µs per loop 

In [466]: %timeit df.pivot(index='user', columns='item', values='rating') 
100 loops, best of 3: 6.38 ms per loop 

In [467]: %timeit df.pivot_table(index='user', columns='item', values='rating') 
100 loops, best of 3: 18.6 ms per loop  

EDIT

для включения недостающих элементов, возможный хак:

def pivotarraywithallitems(df): 
    users,i= np.unique(df['user'],return_inverse=True) 
    item,j= np.unique(df['item'],return_inverse=True) 
    miss= (~in1d(arange(1,6),item)).cumsum() 
    j+=miss[j] 
    a=zeros((len(users),len(item)+miss[-1]),float)*NaN 
    a[i,j]=df['rating'] 
    return a 
0

Вы можете использовать pivot:

print df.pivot(index='user', columns='item', values='rating') 
item 1 3 4 5 
user     
1 NaN 2 5 NaN 
2  5 NaN NaN NaN 
3  3 NaN NaN 1 
4  1 NaN 4 NaN 

Затем вам нужно добавить недостающие столбцы - найти min и max значения, создать диапазон для ярлыка параметра в reindex_axis:

print df['item'].min() 
1 

print df['item'].max() 
5 

rng = range(df['item'].min(), df['item'].max() + 1) 
print rng 
[1, 2, 3, 4, 5] 

print df.pivot(index='user',columns='item',values='rating').reindex_axis(labels=rng, axis=1) 
item 1 2 3 4 5 
user      
1 NaN NaN 2 5 NaN 
2  5 NaN NaN NaN NaN 
3  3 NaN NaN NaN 1 
4  1 NaN NaN 4 NaN 

Последнего использование values для создания numpy array :

print df.pivot(index='user', columns='item', values='rating') 
     .reindex_axis(labels=rng, axis=1) 
     .values 

[[ nan nan 2. 5. nan] 
[ 5. nan nan nan nan] 
[ 3. nan nan nan 1.] 
[ 1. nan nan 4. nan]] 
+0

благодарю вас за ответ. Я получил значение ValueError: Index содержит повторяющиеся записи, не может изменить форму ошибки. Я не добавлял отсутствующих столбцов, поскольку это не было необходимо. Есть ли у вас какие-либо идеи? Благодарю. –

+0

Очень распространенная ошибка и решение 'pivot_table' с' aggfunc'. Dont forget 'default 'aggfunc' is' np.mean' – jezrael

2

Вам нужен поворотный стол:

>>> df.pivot_table(index='user', columns='item', values='rating') 
     1 3 4 5 
user     
1 NaN 2 5 NaN 
2  5 NaN NaN NaN 
3  3 NaN NaN 1 
4  1 NaN 4 NaN 

Обратите внимание, что Totally NaN столбцы присутствуют; Вы можете индексировать, чтобы включить их в случае необходимости:

>>> df.pivot_table(index='user', columns='item', values='rating') 
     .reindex_axis([1, 2, 3, 4, 5], axis=1) 

item 1 2 3 4 5 
user      
1 NaN NaN 2 5 NaN 
2  5 NaN NaN NaN NaN 
3  3 NaN NaN NaN 1 
4  1 NaN NaN 4 NaN 

Чтобы поместить эти значения в массив NumPy, доступ к .values атрибут:

_.values # _ is the last returned value in the repr 
+0

Лучше использовать 'pivot_table' как' pivot'? – jezrael

+0

У меня точно такой же вопрос - что быстрее для такого простого случая? MaxU

+1

'pivot_table' медленнее, чем' pivot' (главным образом потому, что он применяет aggfunc к значениям данных и поддерживает иерархическую индексацию). Поэтому, если ваш приоритет - производительность, вы, вероятно, должны использовать последний. Если вы хотите контролировать, как агрегируются значения (среднее значение, сумма и т. Д.), Тогда «pivot_table» - это путь.Для самого простого случая в вопросе, предложение @ jezrael 'pivot' кажется подходящим. –

Смежные вопросы