Панды: Пользовательская функция группировки - PullRequest
0 голосов
/ 29 декабря 2018

Я ищу пользовательскую функцию группировки, которая собирается группировать строки таким образом, что:

  • Если есть какое-либо число и 0, оно добавит число.
  • Если есть два числа (они будут все время одинаковыми), то это добавит число.
  • Если есть NaN и NaN, оно добавит NaN.
  • Если есть число и NaN, оно добавит число.

Пример, чтобы прояснить ситуацию:

start_df = pd.DataFrame({"id": [1,1,2,2,3,3,4,4,4,5],
                         "foo": [4, 4, np.nan, 7, np.nan, np.nan, 0, 9, 9, 7],
                         "bar": [np.nan, np.nan, 0, 4, 0, 1, 6, 6, 0, 4]})

    id  foo  bar
0   1   4.0  NaN
1   1   4.0  NaN
2   2   NaN  0.0
3   2   7.0  4.0
4   3   NaN  0.0
5   3   NaN  1.0
6   4   0.0  6.0
7   4   9.0  6.0
8   4   9.0  0.0
9   5   7.0  4.0

После пользовательского группирования по id:

result_df = pd.DataFrame({"id": [1,2,3,4,5], "foo": [4, 7, np.nan, 9, 7], "bar": [np.nan, 4, 1, 6, 4]})


    id  foo  bar
0   1   4.0  NaN
1   2   7.0  4.0
2   3   NaN  1.0
3   4   9.0  6.0
4   5   7.0  4.0

Одно известное мне решение:

start_df.groupby("id").max().reset_index()

Но это слишком медленно для моего случая, так как фрейм данных, с которым я имею дело, огромен,С другой стороны, я не могу охватить крайний случай, когда оба элемента являются числами с этим решением:

start_df.groupby("id").sum(min_count=1).reset_index()

С нетерпением жду вашей помощи!

Ответы [ 3 ]

0 голосов
/ 29 декабря 2018

Я полагаю, что решение, которое вы ищете, подходит идеально.

Я добавил следующий другой подход: указание as_index=False в groupby сохраняет исходный индекс, используя groupby.GroupBy.nth

>>> start_df.groupby('id',  as_index=False).nth(1)
   id  foo  bar
1   1  4.0  NaN
3   2  7.0  4.0
5   3  NaN  1.0
7   4  9.0  6.0

ИЛИ

>>> start_df.groupby(['id'], sort=False).max().reset_index()
   id  foo  bar
0   1  4.0  NaN
1   2  7.0  4.0
2   3  NaN  1.0
3   4  9.0  6.0
0 голосов
/ 29 декабря 2018

вот еще один подход не с groupby, но я не могу сказать, является ли он более эффективным.Идея состоит в том, чтобы иметь одинаковое количество строк для каждого идентификатора, чтобы иметь возможность reshape данных и использовать np.nanmax над осью.Для этого вы можете сгенерировать фрейм данных с пропущенными значениями в виде nan.

#create the count of each id
s = start_df.id.value_counts()
nb_max = s.max()
#ceate the dataframe with nan
df_nan = pd.DataFrame({col: np.nan if col != 'id' 
                                   else [ids for ids, val in zip(s.index,nb_max-s.values) 
                                             for _ in range(val)] 
                       for col in start_df.columns })
#get the result
result_df = pd.DataFrame( np.nanmax( pd.concat([start_df, df_nan])[start_df.columns]
                                       .sort_values('id').values
                                       .reshape((-1,start_df.shape[1],nb_max)), 
                                     axis=1), 
                          columns = start_df.columns)

Примечание: вы получите предупреждение о том, что некоторые срезы только nan, но это работает, возможно, есть способмолчать это предупреждение.

0 голосов
/ 29 декабря 2018

Возможно, не то, что вы бы подумали, но это должно сработать

start_df.groupby('id').max()

Используйте reset_index, если хотите вернуть id в столбцы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...