Сжатие pandas DataFrame, чтобы иметь ненулевые значения и изменить имена столбцов - PullRequest
2 голосов
/ 29 мая 2020

У меня есть следующий образец DataFrame

import numpy as np
import pandas as pd

df = pd.DataFrame({'Tom': [2, np.nan, np.nan], 
                   'Ron': [np.nan, 5, np.nan],
                   'Jim': [np.nan, np.nan, 6],
                   'Mat': [7, np.nan, np.nan],}, 
                   index=['Min', 'Max', 'Avg'])

, который выглядит так, где каждая строка имеет только одно ненулевое значение

    Tom Ron Jim Mat
Min 2.0 NaN NaN 7.0
Max NaN 5.0 NaN NaN
Avg NaN NaN 6.0 NaN

Желаемый результат

Для каждого столбца я хочу иметь ненулевое значение, а затем добавить индекс соответствующего ненулевого значения к имени столбца . Таким образом, окончательный результат должен выглядеть следующим образом:

    Tom_Min Ron_Max Jim_Avg Mat_Min
0     2.0    5.0      6.0    7.0

Моя попытка

Использование списков: найдите ненулевое значение и добавьте соответствующий индекс к имени столбца, а затем создайте новый DataFrame

values = [df[col][~pd.isna(df[col])].values[0] for col in df.columns]

# [2.0, 5.0, 6.0, 7.0]

new_cols = [col + '_{}'.format(df[col][~pd.isna(df[col])].index[0]) for col in df.columns]

# ['Tom_Min', 'Ron_Max', 'Jim_Avg', 'Mat_Min']

df_new = pd.DataFrame([values], columns=new_cols)

Мой вопрос

Есть ли какие-то встроенные функции в pandas, которые могут сделать это без использования для циклов и понимания списков?

Ответы [ 2 ]

1 голос
/ 29 мая 2020

Используйте:

s = df.T.stack()
s.index = s.index.map('_'.join)
df = s.to_frame().T

Результат:

# print(df)

   Tom_Min  Ron_Max  Jim_Avg  Mat_Min
0      2.0      5.0      6.0      7.0
1 голос
/ 29 мая 2020

Если есть только одно не пропущенное значение, используйте DataFrame.stack с преобразованием Series в DataFrame, а затем flatten MultiIndex, для правильного порядка используется DataFrame.swaplevel с DataFrame.reindex:

df = df.stack().to_frame().T.swaplevel(1,0, axis=1).reindex(df.columns, level=0, axis=1)
df.columns = df.columns.map('_'.join)
print (df)
   Tom_Min  Ron_Max  Jim_Avg  Mat_Min
0      2.0      5.0      6.0      7.0
...