Ячейка, использующая кумулятивную сумму, а не наблюдения в python

#python #pandas

#python #pandas

Вопрос:

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

 Weight
1
1
0.75
0.5
0.25
0.5
1
1
1
1
  

Я хочу создать две ячейки и добавить столбец в свой фрейм данных, который показывает, в какой ячейке находится каждая строка, но я не хочу привязывать наблюдения (т. Е. Первые 5 наблюдений попали в ячейку 1, а последние пять — в ячейку 2). Вместо этого я хочу создать ячейку таким образом, чтобы сумма весов для каждой ячейки была равна или как можно ближе к равной, насколько это возможно, без изменения порядка столбца.

Итак, я хочу, чтобы результат был

 Weight  I want  Not this
1          1       1
1          1       1
0.75       1       1
0.5        1       1
0.25       1       1
0.5        1       2
1          2       2
1          2       2
1          2       2
1          2       2
  

Есть ли что-то встроенное в Pandas, которое уже делает это, или кто-нибудь может поделиться какими-либо идеями о том, как это сделать? Спасибо!

Ответ №1:

Это должно сделать это:

 df = pd.DataFrame(
        {'Weight': [1, 1, 0.75, 0.5, 0.25, 0.5, 1, 1, 1, 1]})
weight_sum = df.Weight.sum()
df['bin'] = 1
df.loc[df.Weight.cumsum() > weight_sum / 2, 'bin'] = 2

print(df)
  

Вывод:

    Weight  bin
0    1.00    1
1    1.00    1
2    0.75    1
3    0.50    1
4    0.25    1
5    0.50    1
6    1.00    2
7    1.00    2
8    1.00    2
9    1.00    2
  

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

1. Ах, это лучше, чем мой подход. Также df['bin'] = np.where(df.Weight.cumsum() > weight_sum / 2, 2, 1] .

Ответ №2:

Вы могли бы использовать pd.cut в cumsum Weights столбце.

 df = pd.DataFrame({'Weight' : [1, 1, 0.75, 0.5, 0.25, 0.5, 1, 1, 1, 1]})

s =  df['Weight'].sum()
pd.cut(df['Weight'].cumsum(), [-1, s/2, s], labels=[1,2])
  

Для s = 8
этого по умолчанию создаются группы (-1, 4] и (4, 8] . (Это математическое обозначение — значение точно 4 будет включено в первую группу)

Вы могли бы выбрать по-другому и поместить значение точно 4 во вторую группу, указав right = False и скорректировав границы, что дает вам группы [0, 4) и [4, 9)

 pd.cut(df['Weight'].cumsum(), [0, s/2, s 1], labels=[1,2], right=False)
  

-1 И s 1 предназначены для указания того, что значение точно 0 или соответственно 8 все еще должно быть в этой группе.