Как создать новые столбцы фрейма данных из существующего столбца и отсортировать значения от наименьшего к наибольшему

#python #pandas #dataframe

Вопрос:

Я хочу найти все значения, превышающие 0, в столбцах от n_1 до n_3 включительно и заполнить их столбцами от new_1 до new_3 включительно в порядке от наименьшего к наибольшему, чтобы столбец new_1 имел наименьшее значение, а new_3наибольшее значение. Если какие-либо столбцы не заполнены из-за недостаточного количества значений для этого, заполните их 0

Я уже задавал подобный вопрос раньше, но ответ не совпадает с ожидаемым результатом

 EVENT_ID    n_1      n_2    n_3
            
143419013   0.00    7.80    12.83
143419017   1.72    20.16   16.08
143419021   3.03    12.00   17.14
143419025   2.63    0.00    2.51
143419028   2.38    22.00   2.96
143419030   0.00    40.00   0.00
 

Ожидаемый Результат:

 EVENT_ID    n_1      n_2    n_3    new_1  new_2   new_3             
143419013   0.00    7.80    12.83  7.80    12.83  0.00
143419017   1.72    20.16   16.08  1.72   16.08   20.16 
143419021   3.03    12.00   17.14  3.03   12.00   17.14
143419025   2.63    0.00    2.51   2.51   13.78   0.00
143419028   2.38    22.00   2.96   2.38   2.96    22.00 
143419030   3.92    40.00   11.23  40.00  0.00    0.00      
 

Это было решением предыдущего вопроса. Приведенное ниже решение создает новый столбец и сортирует значения от 0 до наибольшего, скорее я хочу, чтобы в новом столбце были значения от 1 и далее. столбец ближе к концу, который не был заполнен из-за недостаточного значения, может быть заполнен 0

 df[['new_1', 'new_2', 'new_3']] = np.sort(
    df[['n_1', 'n_2', 'n_3']].fillna(0),
    axis=1
)
 

Ответ №1:

Нули в конце

Применил подход, аналогичный исходному решению, близкому к решению:

 import pandas as pd
import numpy as np
data = [(143419013,0.00,7.80,12.83),
(143419017,1.72,20.16,16.08),
(143419021,3.03,12.00,17.14),
(143419025,2.63,0.00,2.51),
(143419028,2.38,22.00,2.96),
(143419030,0.00,40.00,0.00)]
df = pd.DataFrame(data, columns=["EVENT_ID", "n_1", "n_2", "n_3"])
df[['new_1', 'new_2', 'new_3']] = np.sort(df[['n_1', 'n_2', 'n_3']] 
    .replace(0.0, np.nan), axis=1)
df.fillna("0.0", inplace=True)
print(df)

    EVENT_ID   n_1    n_2    n_3  new_1  new_2  new_3
0  143419013  0.00   7.80  12.83   7.80  12.83    0.0
1  143419017  1.72  20.16  16.08   1.72  16.08  20.16
2  143419021  3.03  12.00  17.14   3.03   12.0  17.14
3  143419025  2.63   0.00   2.51   2.51   2.63    0.0
4  143419028  2.38  22.00   2.96   2.38   2.96   22.0
5  143419030  0.00  40.00   0.00  40.00    0.0    0.0
 

Этапы этого подхода:

  1. Создайте копию исходных столбцов n_1 — n_3 с заменой 0.0 на NaN («не число»).
  2. Отсортируйте их (НаН заканчивается в конце)
  3. Добавьте их в качестве новых полей в фрейм данных (включая значения NaN).
  4. Замените все значения NaN в кадре данных на 0.0 (с помощью fillna )

(Работает в крайне маловероятном случае, если любое из ваших исходных значений равно бесконечности!)


Что-нибудь

Приведенное выше решение не совсем точно отвечает вопросу, так как предполагается, что оно сортирует элементы от 1 и далее, а не элементы, отличные от нуля.

Эта немного более неуклюжая версия выдает только значения от 1 или больше. Не уверен, какая версия действительно требуется.

 data = [(143419013,0.00,7.80,12.83),
(143419017,1.72,20.16,16.08),
(143419021,3.03,12.00,17.14),
(143419025,2.63,0.00,2.51),
(143419028,2.38,22.00,2.96),
(143419030,0.00,40.00,0.00),
# Extra example row, with a negative value, and a value between 0 and 1
(143419030,-1.00,0.40,27.00)]
df = pd.DataFrame(data, columns=["EVENT_ID", "n_1", "n_2", "n_3"])
df[['new_1', 'new_2', 'new_3']] = np.sort(df[['n_1', 'n_2', 'n_3']] 
    .applymap(lambda v : v if v >= 1 else np.nan), axis=1)
df.fillna("0.0", inplace=True)
print(df)

    EVENT_ID   n_1    n_2    n_3  new_1  new_2  new_3
0  143419013  0.00   7.80  12.83   7.80  12.83    0.0
1  143419017  1.72  20.16  16.08   1.72  16.08  20.16
2  143419021  3.03  12.00  17.14   3.03   12.0  17.14
3  143419025  2.63   0.00   2.51   2.51   2.63    0.0
4  143419028  2.38  22.00   2.96   2.38   2.96   22.0
5  143419030  0.00  40.00   0.00  40.00    0.0    0.0
6  143419030 -1.00   0.40  27.00  27.00    0.0    0.0
 

Комментарии:

1. вы просто упростили весь процесс, как и предполагалось. спасибо за ваш ответ. Я никогда не знал, что существует функция вызова applymap

2. Нет проблем, спасибо за обратную связь.

Ответ №2:

Хитрость здесь в том, чтобы заменить 0.0 на np.inf, отсортировать значения в порядке возрастания и откатить замененные значения:

 new_df = df.filter(like='n_') 
           .replace(0., np.inf) 
           .apply(sorted, axis=1, result_type='expand') 
           .replace(np.inf, 0.0)

new_df.columns = ['new_1', 'new_2', 'new_3']

out = pd.concat([df, new_df], axis=1)
 
 >>> out
    EVENT_ID   n_1    n_2    n_3  new_1  new_2  new_3
0  143419013  0.00   7.80  12.83   7.80  12.83   0.00
1  143419017  1.72  20.16  16.08   1.72  16.08  20.16
2  143419021  3.03  12.00  17.14   3.03  12.00  17.14
3  143419025  2.63   0.00   2.51   2.51   2.63   0.00
4  143419028  2.38  22.00   2.96   2.38   2.96  22.00
5  143419030  0.00  40.00   0.00  40.00   0.00   0.00
 

Комментарии:

1. Если кто-то знает лучший способ переименования столбцов, не стесняйтесь редактировать мой пост

2. Не думайте, что вам нужно lambda здесь; вы можете просто сделать .apply(sorted, axis=1...