Pandas: группировать строки по сходному значению столбца

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

#python-3.x #pandas #фрейм данных #pandas-groupby

Вопрос:

Наличие pandas df, который выглядит следующим образом:

       x  column     word  size  y   
0  1552       0    word1   218  2           
1  1775       1    word2    53  2        
2  1999       2    word3   163  2               
3  2200       3    word4   142  2                
4  2345       4    word5   129  2 
  

Я хотел бы сгруппировать строки на основе условия:
abs(current_row_x current_row_size - next_row_x) < 10

Итак, желаемый df здесь будет:

       x  column     word         size  y   
0  1552       0     word1 word2   271  2                   
1  1999       2     word3         163  2               
3  2200       3     word4 word5   271  2                
  

К настоящему времени я уже пробовал следующее:

 df = df.groupby((abs(df.x   df.size - df.x.shift(1)) < 10).cumsum()).agg({'y':'min', 'x':'min', 'size':'sum', 'column':'min', 'word':' '.join}) 
                                                                                                   
                                                                                                        
  

Но результат df не совсем то, что я ожидаю, а также условие groupby, похоже, игнорируется.

Любой возможный подход к этому? Спасибо

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

1. Вы уверены, что это условие настроено правильно? Мой вывод не соответствует.

2. Группа на основе abs(current_row_x current_row_size - next_row_x) < 10 — это то, чего я хочу достичь. x — это место, где начинается слово, size — это размер слова. Поэтому, если размер x достаточно близок к следующему слову ( x из следующей строки df), я хочу их сгруппировать. Возможно df = df.groupby((abs(df.x df.size - df.x.shift(1)) < 10).cumsum()).agg({'y':'min', 'x':'min', 'size':'sum', 'column':'min', 'word':' '.join}) , подход совершенно неправильный. Я пробовал разные подходы, но безуспешно. Цель состоит в том, чтобы получить желаемый df.

Ответ №1:

Я не получаю тот же результат, но попробуйте:

 s = abs(df['x']   df['size'] - df['x'].shift(-1)) < 10
df = df.groupby(s).agg({'x' : 'first', 'column' : 'first',
                        'word' : lambda x: ' '.join(list(x)), 'size' : 'sum', 'y' : 'first'})
df

Out[1]: 
          x  column               word  size  y
False  1775       1  word2 word3 word5   345  2
True   1552       0        word1 word4   360  2
  

В качестве альтернативы, с .groupby помощью и .cumcount :

 s = df.groupby((abs(df['x']   df['size'] - df['x'].shift(-1)) < 10)).cumcount()
df = df.groupby(s).agg({'x' : 'first', 'column' : 'first',
                        'word' : lambda x: ' '.join(list(x)), 'size' : 'sum', 'y' : 'first'})
df
Out[2]: 
      x  column         word  size  y
0  1552       0  word1 word2   271  2
1  1999       2  word3 word4   305  2
2  2345       4        word5   129  2
  

наконец, с .cumsum() помощью (кажется, я получаю все, кроме выходных данных, которые вы опубликовали 🙂 !):

 s = ((abs(df['x']   df['size'] - df['x'].shift(-1)) < 10)).cumsum()
df = df.groupby(s).agg({'x' : 'first', 'column' : 'first',
                        'word' : lambda x: ' '.join(list(x)), 'size' : 'sum', 'y' : 'first'})
df
Out[2]: 
      x  column               word  size  y
1  1552       0  word1 word2 word3   434  2
2  2200       3        word4 word5   271  2
  

Ответ №2:

После нескольких часов борьбы я заставил это работать.

Построение из этого df:

       x  column     word  size  y   
0  1552       0    word1   218  2           
1  1775       1    word2    53  2        
2  1999       2    word3   163  2               
3  2200       3    word4   142  2                
4  2345       4    word5   129  2 
  

Первое, что я сделал, это добавил еще один столбец x1, представляющий сумму x и size:

 df["x1"] = df["x"]   df["size"]
  

Итак, теперь мой df выглядит так:

       x  column   word  size  y    x1
0  1552       0  word1   218  2  1770
1  1775       1  word2    53  2  1828
2  1999       2  word3   163  2  2162
3  2200       3  word4   142  2  2342
4  2345       4  word5   129  2  2474
  

Теперь я выполняю группировку с этим условием (df.x - df.x1.shift(1)) > 10) :

 df = df.groupby(((df.x - df.x1.shift(1)) > 10).cumsum()).agg({'y':'min', 'x':'min', 'size':'sum', 'column':'min', 'word':' '.join})
  

И результат будет ожидаемым:

    y     x  size  column         word
0  2  1552   271       0  word1 word2
1  2  1999   163       2        word3
2  2  2200   271       3  word4 word5
  

Получилось, но я действительно не знаю, почему условие (abs(df.x df.size - df.x.shift(1)) < 10) объединения не выполнялось. Может быть, кто-то с большим опытом может объяснить.