4
votes

Numpy: création d'une séquence de longueur variable à partir d'une trame de données pandas

Disons que j'ai le bloc de données suivant:

np_pros = np.array([[[0, 99, 77], [5, 11, 88]], [[0, 22, 22], [7, 33, 66], [11, 44, 55]], [[0, 22, 33]]])

Ce que je veux réaliser est de créer un tableau numpy en 3 dimensions tel que le résultat soit le suivant:

XXX

En d'autres termes, le tableau 3D doit avoir la forme suivante [unique_ids, None, feature_size] . Dans mon cas, le nombre de uniques_ids est de 3, la taille de la fonctionnalité est de 3 (toutes les colonnes sauf le person_id ) et le y La colonne est de longueur variable et indique le nombre de mesures pour un person_id.

Je suis bien conscient que je peux créer un np.zeros ((unique_ids, max_num_features, feature_size)) , remplissez-le puis supprimez les éléments dont je n'ai pas besoin mais je veux quelque chose de plus rapide. La raison en est que ma trame de données réelle est énorme (environ [50000, 455] ), ce qui donnera un tableau numpy d'environ [12500, 200, 455].

Dans l'attente de vos réponses!


7 commentaires

Je ne pense pas que vous puissiez créer un tableau comme ça, chacun des tableaux internes a des tailles différentes, la taille du groupe. Vous pourriez cependant avoir une liste.


@DanielMesejo alors que proposez-vous? Qu'est-ce qui serait optimal à la fois en mémoire et en complexité?


Que voulez-vous faire ensuite?


C'est une bonne question. Une fois que j'ai les séquences, je souhaite effectuer un bucketing avec Tensorflow pour remplir dynamiquement les séquences.


C'est pourquoi je veux strictement me retrouver avec un tableau de longueur variable (pour compléter ensuite dans un lot).


Pourriez-vous ajouter ce que la sortie cherche à compléter?


continuons cette discussion dans le chat .


3 Réponses :


2
votes

Voici une façon de procéder:

np.split(df1.drop('person_id', axis=1).values, ix[1:])

[array([[ 0, 99, 77],
        [ 5, 11, 88]], dtype=int64), 
 array([[ 0, 22, 22],
        [ 7, 33, 66],
        [11, 44, 55]], dtype=int64), 
 array([[ 0, 22, 33]], dtype=int64)]

Détails

Utilisez np.flatnonzero après avoir comparé df1 avec un version de lui-même ( pd.shift code> ) afin d'obtenir les indices où les changements dans person_id ont lieu:

ix = np.flatnonzero(df1.person_id != df1.person_id.shift(1))
#array([0, 2, 5])

Utilisez np.split afin de diviser les colonnes d'intérêt du dataframe en fonction de l'index obtenu:

ix = np.flatnonzero(df1.person_id != df1.person_id.shift(1))
np.split(df1.drop('person_id', axis=1).values, ix[1:])

[array([[ 0, 99, 77],
        [ 5, 11, 88]], dtype=int64), 
 array([[ 0, 22, 22],
        [ 7, 33, 66],
        [11, 44, 55]], dtype=int64), 
 array([[ 0, 22, 33]], dtype=int64)]


0 commentaires

2
votes

Vous pouvez utiliser groupby :

[array([[  0, 101,  99,  77],
       [  5, 101,  11,  88]]), array([[  0, 102,  22,  22],
       [  7, 102,  33,  66],
       [ 11, 102,  44,  55]]), array([[  0, 103,  22,  33]])]

import pandas as pd

df_raw = pd.DataFrame({"person_id": [101, 101, 102, 102, 102, 103], "date": [0, 5, 0, 7, 11, 0], "val1": [99, 11, 22, 33, 44, 22], "val2": [77, 88, 22, 66, 55, 33]})

result = [group.values for _, group in df_raw.groupby('person_id')[['date', 'val1', 'val2']]]
print(result)


0 commentaires

0
votes

Une autre solution avec xarray


créons la dimension impliquée par la duplicité de personne_id

>>> ar = xa.to_array().T.values
>>> ar
array([[[ 0., 99., 77.],
        [ 5., 11., 88.],
        [nan, nan, nan]],

       [[ 0., 22., 22.],
        [ 7., 33., 66.],
        [11., 44., 55.]],

       [[ 0., 22., 33.],
        [nan, nan, nan],
        [nan, nan, nan]]])

Par souci de lisibilité , nous pourrions vouloir transformer df en un xarray.Dataset -objet

>>> xa = df.to_xarray()
>>> xa
<xarray.Dataset>
Dimensions:    (newdim: 3, person_id: 3)
Coordinates:
  * newdim     (newdim) float64 0.0 1.0 2.0
  * person_id  (person_id) int64 101 102 103
Data variables:
    date       (newdim, person_id) float64 0.0 0.0 0.0 5.0 7.0 nan nan 11.0 nan
    val1       (newdim, person_id) float64 99.0 22.0 22.0 11.0 33.0 nan nan ...
    val2       (newdim, person_id) float64 77.0 22.0 33.0 88.0 66.0 nan nan ...

puis dans un dimensionally-healthy numpy array

>>> df['newdim'] = df.person_id.duplicated()
>>> df.newdim    = df.groupby('person_id').newdim.cumsum()
>>> df           = df.set_index(["newdim", "person_id"])
>>> df
                  date  val1  val2
newdim person_id                  
0.0    101           0    99    77
1.0    101           5    11    88
0.0    102           0    22    22
1.0    102           7    33    66
2.0    102          11    44    55
0.0    103           0    22    33

Notez que les valeurs nan ont été introduites par coercition.


0 commentaires