Использование groupby и фильтров для фрейма данных

#python-3.x #dataframe #pandas-groupby #data-filtering

#python-3.x #фрейм данных #pandas-groupby #фильтрация данных

Вопрос:

У меня есть фрейм данных как со строковыми, так и с целочисленными значениями.

Прикрепление образца словаря данных для понимания фрейма данных, который у меня есть:

 data = {
'col1': ['A','A','A','B','B','B','C','C','C','D','D','D'],
'col2': [10,20,30,10,20,30,10,20,30,10,20,30],
'col3': ['X','X','X','X','Y','X','X','X','Y','Y','X','X'],
'col4': [45,23,78,56,12,34,87,54,43,89,43,12]
'col5': [3,4,6,4,3,2,4,3,5,3,4,6]
}
 

Мне нужно извлечь данные, как указано ниже:

  • Максимальное значение из col4
  • Сгруппировано по col1
  • Отфильтровывается col3 из результата, если значение равно Y
  • Отфильтруйте col5 из результата, чтобы отображать только значения не более 5.

Итак, я попробовал кое-что и столкнулся со следующими проблемами.

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

 print(dataframe['col4'].max()) #this worked to get one max value
print(dataframe.groupby('col1').max() #this doesn't work
 

Второй вариант не работает для меня, поскольку он также возвращает максимальное значение для col2. Мне нужно, чтобы результат имел значение col2 против максимальной строки в каждой группе.

2- Я не могу применить фильтр как к col3 (str), так и к col5 (int) в одной команде. Есть какой-нибудь способ это сделать?

 print(dataframe[dataframe['col3'] != 'Y' amp; dataframe['col5'] < 6]) #generates an error
 

Результат, который я ожидаю от этого:

     col1  col2 col3  col4  col5
0     A    10    X    45     3
3     B    10    X    56     4
6     C    10    X    87     4
10    D    20    X    43     4
#
# 78 is max in group A, but ignored as col5 is 6 (we need < 6)
# Similarly, 89 is max in group D, but ignored as col3 is Y.
 

Прошу прощения, если я делаю что-то не так. Я совсем новичок в этом.

Спасибо.

Ответ №1:

Я не разработчик python, но, по моему мнению, вы делаете это неправильно. Вместо структуры списка у вас должен быть список структуры. Затем вы можете начать работать с таким списком.

Это пример решения, так что, вероятно, это можно было бы сделать гораздо более плавным способом:

 data = {
'col1': ['A','A','A','B','B','B','C','C','C','D','D','D'],
'col2': [10,20,30,10,20,30,10,20,30,10,20,30],
'col3': ['X','X','X','X','Y','X','X','X','Y','Y','X','X'],
'col4': [45,23,78,56,12,34,87,54,43,89,43,12],
'col5': [3,4,6,4,3,2,4,3,5,3,4,6]
}

newData = [];

for i in range(len(data['col1'])):
    newData.append({'col1' : data['col1'][i], 'col2' : data['col2'][i], 'col3' : data['col3'][i], 'col4' : data['col4'][i], 'col5' : data['col5'][i]})

withoutY = list(filter(lambda d: d['col3'] != 'Y', newData))
lessThen5 = list(filter(lambda d: d['col5'] < 5, withoutY))
values = set(map(lambda d: d['col1'], lessThen5))
groupped = [[d1 for d1 in lessThen5 if d1['col1']==d2] for d2 in values]

result = [];
for i in range(len(groupped)):
    result.append(max(groupped[i], key = lambda g: g['col4']))

sortedResult = sorted(result, key = lambda r: r['col1'])

print (sortedResult)
 

Результат:

 [
{'col1': 'A', 'col2': 10, 'col3': 'X', 'col4': 45, 'col5': 3}, 
{'col1': 'B', 'col2': 10, 'col3': 'X', 'col4': 56, 'col5': 4}, 
{'col1': 'C', 'col2': 10, 'col3': 'X', 'col4': 87, 'col5': 4}, 
{'col1': 'D', 'col2': 20, 'col3': 'X', 'col4': 43, 'col5': 4}
]
 

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

1. Привет @Grzegorz У меня нет данных в формате dict, указанном в вопросе. Я просто поделился этим, чтобы другие могли получить данные и использовать их для анализа моей проблемы. У меня есть данные в формате фрейма данных pandas, и мне нужно выработать решение на основе этого.

Ответ №2:

Хорошо, я на самом деле не заметил. Итак, я попробовал что-то вроде этого:

 #fd is a filtered data
fd=data.query('col3 != "Y"').query('col5 < 6')
# or fd=data[data.col3 != 'Y'][data.col5 < 6]
#m is max for col4 grouped by col1
m=fd.groupby('col1')['col4'].max()
 

Это сгруппирует по col1 и получит максимум из col4, но в результате мы получим 2 столбца (col1 и col4).
Я не знаю, чего ты хочешь добиться.
Если вы хотите иметь всю строку, вот код:

 result=fd[lambda x: x.col4 == m.get(x.col1).values]
 

Вам нужно быть осторожным, потому что у вас не всегда будет одна строка для «col1».
Например, для данных

 data = pd.DataFrame({
    'col1': ['A','A','A','A','B','B','B','B','C','C','C','D','D','D'],
    'col2': [20,10,20,30,10,20,20,30,10,20,30,10,20,30],
    'col3': ['X','X','X','X','X','X','Y','X','X','X','Y','Y','X','X'],
    'col4': [45,45,23,78,45,56,12,34,87,54,43,89,43,12],
    'col5': [1,3,4,6,1,4,3,2,4,3,5,3,4,6]})
 

Результатом будет:

    col1  col2 col3  col4  col5
0     A    20    X    45     1
1     A    10    X    45     3
5     B    20    X    56     4
8     C    10    X    87     4
12    D    20    X    43     4
 

Кроме того, если вы хотите иметь обычный индекс вместо …, 8, 9 12, вы можете использовать «where» вместо «query».