Как преобразовать повторяющиеся пронумерованные столбцы в Pandas в одиночные ненумерованные столбцы? - PullRequest
2 голосов
/ 17 июня 2020

Приношу извинения за (потенциально) плохой заголовок, но мне трудно понять, как это описать. У меня есть набор данных, который при чтении в pandas фрейм данных имеет примерно следующую форму:

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

Каждая пара столбцов с одинаковым номером представляет позиции (X, Y) для объекта в заданная временная метка. Каждая строка представляет новую метку времени. Что я хотел бы сделать, так это преобразовать этот фрейм данных во что-то вроде этого:

   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

Теперь я знаю, что могу извлечь соответствующую информацию из столбца names и повторить это так:

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)

Это дает нечто близкое к первой части того, что я хочу:

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

Но, к сожалению, я застреваю, когда думаю, как переместить точки (X, Y) в их правильные позиции в фрейме данных. Я знаю, что есть способы сделать это, перебирая весь фрейм данных и устанавливая для каждой ячейки фрейма данных соответствующее значение, но они кажутся неэффективными, особенно с учетом того, что наборы данных будут в мегабайтах информации, а у меня плохая (время выполнения) опыт использования "C -подобных" методов зацикливания в Pandas.

Простой ответ - «изменить набор данных», но, к сожалению, я не контролирую, как он создается: (

Любая помощь приветствуется! Мои извинения, если это репост.

Ответы [ 2 ]

3 голосов
/ 17 июня 2020

Сначала мы преобразовываем индекс столбца в MultiIndex, а затем stack первый уровень в столбцы. Наконец, мы rename новые столбцы:

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


Edit : Как прокомментировано sammywemmy ниже, вы можете упростить первую строку до
df.columns = df.columns.str.split('_', expand=True)
1 голос
/ 17 июня 2020

Вот 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...