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!
3 Réponses :
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)]
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)
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.
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 .