Как применять "первые" и "последние" функции к столбцам при использовании группы в pandas?
У меня есть кадр данных, и я хотел бы сгруппировать его по определенному столбцу (или, другими словами, по значениям из определенного столбца). Я могу сделать это следующим образом: grouped = df.groupby(['ColumnName'])
.
Я представляю результат этой операции как таблицы, в которой некоторые ячейки могут содержать наборы значений вместо одиночных значений. Чтобы получить обычную таблицу (т.е. Таблицу, в которой каждая ячейка содержит только одно единственное значение), мне нужно указать, какую функцию я хочу использовать для преобразования наборов значений в ячейках в отдельные значения.
Например, я могу заменить наборы значений по их сумме или по их минимальному или максимальному значению. Я могу сделать это следующим образом: grouped.sum()
или grouped.min()
и т.д.
Теперь я хочу использовать разные функции для разных столбцов. Я понял, что могу сделать это следующим образом: grouped.agg({'ColumnName1':sum, 'ColumnName2':min})
.
Однако по некоторым причинам я не могу использовать first
. Более подробно, grouped.first()
работает, но grouped.agg({'ColumnName1':first, 'ColumnName2':first})
не работает. В результате я получаю NameError: NameError: name 'first' is not defined
. Итак, мой вопрос: почему это происходит и как решить эту проблему.
ADDED
Здесь я нашел следующий пример:
grouped['D'].agg({'result1' : np.sum, 'result2' : np.mean})
Может быть, мне также нужно использовать np
? Но в моем случае python не распознает "np". Должен ли я импортировать его?
Ответы
Ответ 1
Я думаю, что проблема в том, что существуют два разных метода first
, которые используют имя, но действуют по-разному: для groupby objects и другой для серии /DataFrame (в зависимости от времени).
Чтобы воспроизвести поведение метода groupby first
над DataFrame с помощью agg
, вы можете использовать iloc[0]
(который получает первую строку в каждой группе (DataFrame/Series) по индексу):
grouped.agg(lambda x: x.iloc[0])
Например:
In [1]: df = pd.DataFrame([[1, 2], [3, 4]])
In [2]: g = df.groupby(0)
In [3]: g.first()
Out[3]:
1
0
1 2
3 4
In [4]: g.agg(lambda x: x.iloc[0])
Out[4]:
1
0
1 2
3 4
Аналогично, вы можете реплицировать last
с помощью iloc[-1]
.
Примечание. Это будет работать со столбцами и другими:
g.agg({1: lambda x: x.iloc[0]})
В старой версии pandas вы могли бы использовать метод irow (например, x.irow(0)
, см. предыдущие изменения.
Несколько обновленных заметок:
Это лучше сделать с помощью метода nth
, который намного быстрее >= 0,13:
g.nth(0) # first
g.nth(-1) # last
Вам нужно немного позаботиться, поскольку поведение по умолчанию для first
и last
игнорирует строки NaN... и IIRC для DataFrame groupbys было прервано до 0.13... там есть опция dropna
для nth
.
Вы можете использовать строки, а не встроенные (хотя IIRC pandas указывает на встроенный sum
и применяет np.sum
):
grouped['D'].agg({'result1' : "sum", 'result2' : "mean"})
Ответ 2
Вместо использования first
или last
используйте их строковые представления в методе agg
. Например, в случае OP:
grouped = df.groupby(['ColumnName'])
grouped['D'].agg({'result1' : np.sum, 'result2' : np.mean})
#you can do the string representation for first and last
grouped['D'].agg({'result1' : 'first', 'result2' : 'last'})
Ответ 3
Я не уверен, действительно ли это проблема, но sum
и min
- это встроенные модули Python, которые принимают некоторые итерации в качестве входных данных, тогда как first
- это метод объекта pandas Series, поэтому возможно, это не в вашем пространстве имен. Кроме того, в качестве ввода требуется что-то другое (документ указывает некоторое значение смещения).
Я предполагаю, что один из способов обойти это - создать свою собственную функцию first
и определить ее так, чтобы в качестве ввода использовался объект Series, например:
def first(Series, offset):
return Series.first(offset)
или что-то в этом роде.