Toutes mes excuses pour le titre (potentiellement) médiocre, mais j'ai du mal à comprendre comment le décrire moi-même. J'ai un ensemble de données qui, lorsqu'il est lu dans un dataframe pandas, a à peu près la forme suivante:

import pandas as pd 
import numpy as np
df_all = pd.DataFrame(np.random.randn(2, 6), columns=["0_X", "0_Y", "1_X", "1_Y", "2_X", "2_Y"])
  0_X       0_Y       1_X       1_Y       2_X       2_Y
0 1.470289  0.588573  1.303684  1.374806  1.025082  0.316623
1 0.426527  2.036558  0.100993  2.485025  0.350100  0.603069

Chaque paire de colonnes avec le même numéro représente les positions (X, Y) d'un objet à un horodatage donné. Chaque ligne représente un nouvel horodatage. Ce que je voudrais faire, c'est transformer ce dataframe en quelque chose comme ceci:

   Time   ObjectId   X         Y 
0  0      0          1.470289  0.588573  
1  0      1          1.303684  1.374806  
2  0      2          1.025082  0.316623
3  1      0          0.426527  2.036558  
4  1      1          0.100993  2.485025  
5  1      2          0.350100  0.603069

Maintenant, je sais que je peux extraire les informations pertinentes de la colonne noms et la répéter comme suit:

obj_ids = []
for each_column in list(df_all.columns):
  obj_id = each_column.split("_")[0]
  if obj_id not in obj_ids:
    obj_ids.append(obj_id)

df_all_rotated = pd.DataFrame()
df_all_rotated["ObjectID"] = obj_ids 
df_all_rotated = pd.concat([df_all_rotated ] * len(df_all.index), ignore_index=True)

Cela produit quelque chose de proche de la première partie de ce que je veux:

      ObjectId   
0     0
1     1
2     2
3     0
4     1
5     2

Mais malheureusement, je reste bloqué lorsque je réfléchis à la manière de déplacer les points (X, Y) vers leurs positions appropriées dans le dataframe. Je sais qu'il existe des moyens de le faire en boucle sur l'intégralité de la trame de données et en définissant chaque cellule de trame de données à sa valeur respective, mais celles-ci semblent inefficaces, d'autant plus que les ensembles de données seront dans les Mo d'informations, et j'ai mauvais (runtime) expériences avec l'utilisation de méthodes de bouclage «de type C» dans Pandas.

La réponse simple est "changer le jeu de données" mais malheureusement je ne contrôle pas comment cela est généré :(

Toute aide est appréciée! Mes excuses si c'est une republication.

2
Darren C. 17 juin 2020 à 00:05

3 réponses

Nous convertissons d'abord l'index de colonne en un MultiIndex, puis stack le premier niveau des colonnes. Enfin, nous rename les nouvelles colonnes:

df = pd.DataFrame(np.random.randn(2, 6), columns=["0_X", "0_Y", "1_X", "1_Y", "2_X", "2_Y"])

df.columns = pd.MultiIndex.from_tuples([c.split('_') for c in df.columns])
df.stack(0).reset_index().rename(columns={'level_0': 'Time', 'level_1': 'ObjectId'})
   Time ObjectId         X         Y
0     0        0  0.862742 -1.642483
1     0        1  0.786022 -0.661986
2     0        2  0.044130  1.054564
3     1        0 -1.415127 -1.197613
4     1        1  0.530939  1.238403
5     1        2  0.495760  0.101748

Éditer
df.columns = df.columns.str.split('_', expand=True)
2
Stef 16 juin 2020 à 21:49

Vous pouvez utiliser melt, puis {{ X0}} dans deux nouvelles colonnes (object_id et variable), et enfin utiliser pivot_table:

df_all["Time"] = df_all.index
t = df_all.melt(id_vars="Time")
t['object_id'], t['variable'] = t['variable'].str.split('_', 1).str
t.pivot_table(index = ["Time","object_id"], columns="variable", values="value").reset_index()

Production:

         Time  object_id         X         Y
0            0         0  0.731062  1.518622
1            0         1  0.518488  0.463068
2            0         2 -1.859968 -0.613835
3            1         0 -0.216921  0.178474
4            1         1 -0.627465  2.395974
5            1         2 -0.273537 -0.898802
0
DavideBrex 16 juin 2020 à 21:25

Voici wide_to_long

df_all.columns=df_all.columns.str.split('_').map(lambda x : ''.join(x[::-1]))

df=pd.wide_to_long(df_all.rename_axis('Time').reset_index(),['X','Y'],i='Time',j='ObjectId',suffix='\\w+').reset_index()
df
Out[89]: 
   Time  ObjectId         X         Y
0     0         0 -0.121748  0.146057
1     1         0  1.883143  0.088054
2     0         1  0.841091 -1.034432
3     1         1  0.444028 -0.711991
4     0         2 -0.677578  1.401241
5     1         2 -0.424676 -0.933622
1
YOBEN_S 16 juin 2020 à 21:40