Étant donné le DataFrame suivant dans les pandas:

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

Je voudrais le transférer dans un tableau numpy, avec la colonne utilisateur comme axe y et la colonne article comme axe x, comme ceci:

    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

Comment puis-je utiliser la fonction apply pour le faire rapidement?

1
user4462740 8 mars 2016 à 16:49

3 réponses

Meilleure réponse

Pour le faire rapidement, faites-le avec des outils 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

Ensuite (vous pouvez remplir un NaN avant si nécessaire):

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

La colonne 2 n'est pas là car il n'y a pas d'élément 2.

Le gain est significatif:

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    

MODIFIER

Pour inclure les éléments manquants, un piratage possible:

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
B. M. 8 mars 2016 à 16:19

Vous pouvez utiliser 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

Ensuite, vous devez ajouter des colonnes manquantes - recherchez les valeurs min et max, créez une plage pour l'étiquette de paramètre dans 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

Dernière utilisation values pour générer 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
jezrael 8 mars 2016 à 14:32

Vous avez besoin d'un tableau croisé dynamique:

>>> 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

Notez que totalement NaN colonnes sont présentes; vous pouvez réindexer pour les inclure si nécessaire:

>>> 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

Pour placer ces valeurs dans un tableau NumPy, accédez à l'attribut .values:

_.values # _ is the last returned value in the repr
2
Alex Riley 8 mars 2016 à 13:59