Функция Pandas Groupby Agg не снижает
Я использую функцию агрегирования, которую я использовал в своей работе уже давно. Идея состоит в том, что если ряд, переданный функции, имеет длину 1 (т. Е. Группа имеет только одно наблюдение), то эти наблюдения возвращаются. Если длина пройденной серии больше единицы, то наблюдения возвращаются в виде списка.
Некоторым это может показаться странным, но это не проблема X,Y, у меня есть веская причина хотеть сделать это, не относящееся к этому вопросу.
Это функция, которую я использовал:
def MakeList(x):
""" This function is used to aggregate data that needs to be kept distinc within multi day
observations for later use and transformation. It makes a list of the data and if the list is of length 1
then there is only one line/day observation in that group so the single element of the list is returned.
If the list is longer than one then there are multiple line/day observations and the list itself is
returned."""
L = x.tolist()
if len(L) > 1:
return L
else:
return L[0]
Теперь по какой-то причине, с текущим набором данных, над которым я работаю, я получаю ValueError, утверждающий, что функция не уменьшается. Вот некоторые тестовые данные и оставшиеся шаги, которые я использую:
import pandas as pd
DF = pd.DataFrame({'date': ['2013-04-02',
'2013-04-02',
'2013-04-02',
'2013-04-02',
'2013-04-02',
'2013-04-02',
'2013-04-02',
'2013-04-02',
'2013-04-02',
'2013-04-02'],
'line_code': ['401101',
'401101',
'401102',
'401103',
'401104',
'401105',
'401105',
'401106',
'401106',
'401107'],
's.m.v.': [ 7.760,
25.564,
25.564,
9.550,
4.870,
7.760,
25.564,
5.282,
25.564,
5.282]})
DFGrouped = DF.groupby(['date', 'line_code'], as_index = False)
DF_Agg = DFGrouped.agg({'s.m.v.' : MakeList})
Пытаясь отладить это, я поместил оператор печати в print L
а также print x.index
и вывод был следующим:
[7.7599999999999998, 25.564]
Int64Index([0, 1], dtype='int64')
[7.7599999999999998, 25.564]
Int64Index([0, 1], dtype='int64')
По какой-то причине кажется, что agg
передает серию дважды в функцию. Насколько я знаю, это вообще ненормально и, вероятно, является причиной того, что моя функция не снижается.
Например, если я напишу такую функцию:
def test_func(x):
print x.index
return x.iloc[0]
Это работает без проблем, и операторы print:
DF_Agg = DFGrouped.agg({'s.m.v.' : test_func})
Int64Index([0, 1], dtype='int64')
Int64Index([2], dtype='int64')
Int64Index([3], dtype='int64')
Int64Index([4], dtype='int64')
Int64Index([5, 6], dtype='int64')
Int64Index([7, 8], dtype='int64')
Int64Index([9], dtype='int64')
Это указывает на то, что каждая группа передается в функцию только один раз в виде серии.
Может кто-нибудь помочь мне понять, почему это не удается? Я успешно использовал эту функцию во многих множествах данных, с которыми я работаю....
Спасибо
2 ответа
Я не могу объяснить вам, почему, но из моего опыта list
в pandas.DataFrame
не все так хорошо работает.
Я обычно использую tuple
вместо. Это будет работать:
def MakeList(x):
T = tuple(x)
if len(T) > 1:
return T
else:
return T[0]
DF_Agg = DFGrouped.agg({'s.m.v.' : MakeList})
date line_code s.m.v.
0 2013-04-02 401101 (7.76, 25.564)
1 2013-04-02 401102 25.564
2 2013-04-02 401103 9.55
3 2013-04-02 401104 4.87
4 2013-04-02 401105 (7.76, 25.564)
5 2013-04-02 401106 (5.282, 25.564)
6 2013-04-02 401107 5.282
Это ошибка в DataFrame. Если агрегатор возвращает список для первой группы, он потерпит неудачу с упомянутой вами ошибкой; если он возвращает не-список (не Series) для первой группы, он будет работать нормально. Неработающий код находится в groupby.py:
def _aggregate_series_pure_python(self, obj, func):
group_index, _, ngroups = self.group_info
counts = np.zeros(ngroups, dtype=int)
result = None
splitter = get_splitter(obj, group_index, ngroups, axis=self.axis)
for label, group in splitter:
res = func(group)
if result is None:
if (isinstance(res, (Series, Index, np.ndarray)) or
isinstance(res, list)):
raise ValueError('Function does not reduce')
result = np.empty(ngroups, dtype='O')
counts[label] = group.shape[0]
result[label] = res
Заметить, что if result is None
а также isinstance(res, list
, Ваши варианты:
Подделка groupby(). Agg(), чтобы он не видел список для первой группы, или
Выполните агрегацию самостоятельно, используя приведенный выше код, но без ошибочного теста.