#python #pandas #columnsorting
#python #pandas #сортировка столбцов
Вопрос:
У меня есть такие данные в фрейме данных Pandas
id import_id investor_id loan_id meta
35736 unremit_loss_100312 Q05 0051765139 {u'total_paid': u'75', u'total_expense': u'75'}
35737 unremit_loss_100313 Q06 0051765140 {u'total_paid': u'77', u'total_expense': u'78'}
35739 unremit_loss_100314 Q06 0051765141 {u'total_paid': u'80', u'total_expense': u'65'}
Как сортировать на основе total_expense, который является значением поля json
, например: total_expense в мета-поле
Вывод должен быть
id import_id investor_id loan_id meta
35739 unremit_loss_100314 Q06 0051765141 {u'total_paid': u'80', u'total_expense': u'65'}
35736 unremit_loss_100312 Q05 0051765139 {u'total_paid': u'75', u'total_expense': u'75'}
35737 unremit_loss_100313 Q06 0051765140 {u'total_paid': u'77', u'total_expense': u'78'}
Комментарии:
1. Попробуйте
df = df.iloc[df['meta'].str.get('total_expense').argsort().values, :]
и посмотрите, работает ли это. Если нет, вам нужно будет показать нам более 1 строки данных.2. это не работает, все строки становятся одинаковыми значениями, если я использую вашу логику. вопрос изменен и добавлен дополнительные строки @coldspeed
3. Я предоставил два варианта. Кажется, вам нужно преобразовать извлеченные значения в целое число перед сортировкой. Посмотрите и, пожалуйста, четко сообщите мне, в чем проблема, если это не сработало. Спасибо.
4. @JameelGrand Я попытался найти простой способ добиться этого, решает ли это вашу проблему?
Ответ №1:
Настройка и предварительная обработка
import ast
import numpy as np
if isinstance(x.at[0, 'meta'], str):
df['meta'] = df['meta'].map(ast.literal_eval)
str.get
с Series.argsort
df.iloc[df['meta'].str.get('total_expense').astype(int).argsort()]
id import_id investor_id loan_id meta
2 35739 unremit_loss_100314 Q06 51765141 {'total_paid': '80', 'total_expense': '65'}
0 35736 unremit_loss_100312 Q05 51765139 {'total_paid': '75', 'total_expense': '75'}
1 35737 unremit_loss_100313 Q06 51765140 {'total_paid': '77', 'total_expense': '78'}
Понимание списка
df.iloc[np.argsort([int(x.get('total_expense', '-1')) for x in df['meta']])]
id import_id investor_id loan_id meta
2 35739 unremit_loss_100314 Q06 51765141 {'total_paid': '80', 'total_expense': '65'}
0 35736 unremit_loss_100312 Q05 51765139 {'total_paid': '75', 'total_expense': '75'}
1 35737 unremit_loss_100313 Q06 51765140 {'total_paid': '77', 'total_expense': '78'}
Если вам нужно обработать NAN / отсутствующие данные, используйте
u = [
int(x.get('total_expense', '-1')) if isinstance(x, dict) else -1
for x in df['meta']
]
df.iloc[np.argsort(u)]
id import_id investor_id loan_id meta
2 35739 unremit_loss_100314 Q06 51765141 {'total_paid': '80', 'total_expense': '65'}
0 35736 unremit_loss_100312 Q05 51765139 {'total_paid': '75', 'total_expense': '75'}
1 35737 unremit_loss_100313 Q06 51765140 {'total_paid': '77', 'total_expense': '78'}
Ответ №2:
Использовать:
print (df)
id import_id investor_id loan_id
0 35736 unremit_loss_100312 Q05 51765139
1 35736 unremit_loss_100312 Q05 51765139
2 35736 unremit_loss_100312 Q05 51765139
meta
0 {u'total_paid': u'75', u'total_expense': u'75'}
1 {u'total_paid': u'75', u'total_expense': u'20'}
2 {u'total_paid': u'75', u'total_expense': u'100'}
import ast
df['meta'] = df['meta'].apply(ast.literal_eval)
df = df.iloc[df['meta'].str['total_expense'].astype(int).argsort()]
print (df)
id import_id investor_id loan_id
1 35736 unremit_loss_100312 Q05 51765139
0 35736 unremit_loss_100312 Q05 51765139
2 35736 unremit_loss_100312 Q05 51765139
meta
1 {'total_paid': '75', 'total_expense': '20'}
0 {'total_paid': '75', 'total_expense': '75'}
2 {'total_paid': '75', 'total_expense': '100'}
Если возможно, если отсутствует total_expense
ключ для какой-либо строки, преобразуйте пропущенные значения в некоторое целое число ниже, как и все другие значения, например -1
, для первой позиции этих строк:
print (df)
id import_id investor_id loan_id
0 35736 unremit_loss_100312 Q05 51765139
1 35736 unremit_loss_100312 Q05 51765139
2 35736 unremit_loss_100312 Q05 51765139
meta
0 {u'total_paid': u'75', u'total_expense': u'75'}
1 {u'total_paid': u'75', u'total_expense': u'20'}
2 {u'total_paid': u'75'}
df['meta'] = df['meta'].apply(ast.literal_eval)
df = df.iloc[df['meta'].str.get('total_expense').fillna(-1).astype(int).argsort()]
print (df)
id import_id investor_id loan_id
2 35736 unremit_loss_100312 Q05 51765139
1 35736 unremit_loss_100312 Q05 51765139
0 35736 unremit_loss_100312 Q05 51765139
meta
2 {'total_paid': '75'}
1 {'total_paid': '75', 'total_expense': '20'}
0 {'total_paid': '75', 'total_expense': '75'}
Другое решение:
df['new'] = df['meta'].str.get('total_expense').astype(int)
df = df.sort_values('new').drop('new', axis=1)
Комментарии:
1. Спасибо за ответ, это приводит все мои строки к одному и тому же значению. ie. все значения моего поля id становятся одинаковыми, обновленный вопрос с большим количеством строк.
2. @JameelGrand — Можете ли вы добавить вывод после моего решения вопроса?
3. @JameelGrand — добавлено новое решение, вы можете его проверить?
4. не повезло: (он выдает несортированный фрейм данных, а df[‘meta’].str.get(‘total_expense’) выдает все значения Nan, фактически не принимая значения
5. @JameelGrand — вы используете
df['meta'] = df['meta'].apply(ast.literal_eval)
как первый шаг? а потомdf['new'] = df['meta'].str.get('total_expense').astype(int)
?
Ответ №3:
РЕДАКТИРОВАТЬ 2:
Найден немного лучший способ сделать это без использования apply:
from pandas.io.json import json_normalize
df = pd.concat([df, json_normalize(df['meta'])], axis = 1)
.sort_values(by = 'total_expense')
.drop(columns = ['total_paid', 'total_expense'])
Редактировать:
df = pd.concat([df, df['meta'].apply(pd.Series)], axis = 1).sort_values(by = 'total_expense').drop(columns = ['total_paid', 'total_expense'])
Если вы хотите, чтобы он выглядел как оригинал, просто удалите столбцы, которые вы объединяете после сортировки.
Оригинал:
df = pd.concat([df, df['meta'].apply(pd.Series)], axis = 1).drop(columns ='meta').sort_values(by = 'total_expense')
df['meta'].apply(pd.Series)
превращает dicts в столбце meta в собственный df. Мы можем объединить его с оригиналом, удалить столбец meta (как избыточный), а затем отсортировать значения по «общему расходу»
Комментарии:
1. @JameelGrand — отредактировал мой комментарий, чтобы он выглядел как исходный df
Ответ №4:
Использование регулярных выражений:
df = pd.read_clipboard(r'ss ')
pattern = r"""u'total_expense': u'([0-9.] )'"""
df['total_expense'] = df.meta.str.extract(pattern)
df.sort_values('total_expense')
Использование apply:
df['total_expense'] = df.meta.apply(eval).apply(
lambda x: x.get('total_expense', -1))
df.sort_values('total_expense')
Вывод:
id import_id investor_id loan_id
2 35739 unremit_loss_100314 Q06 51765141
0 35736 unremit_loss_100312 Q05 51765139
1 35737 unremit_loss_100313 Q06 51765140
meta total_expense
2 {u'total_paid': u'80', u'total_expense': u'65'} 65
0 {u'total_paid': u'75', u'total_expense': u'75'} 75
1 {u'total_paid': u'77', u'total_expense': u'78'} 78