В примере, который вы даете с помощью
df = pd.DataFrame({'V1':[100000,50000, 20000, 30000,
150000, 30000, 20000, 200000]},
index=range(1,9))
Из того, что я понимаю, " получите индексы, где каждый раз, когда сумма V1 достигает 50k точно ", вы можетеСделайте это, создав столбец с числом ровно 50 тыс., которое у вас есть в сумме до каждой строки:
ser_50k = (df.V1.cumsum()/50000).astype(int)
df['nb_50'] = (ser_50k - ser_50k.shift()).fillna(ser_50k).astype(int)
Теперь вы можете использовать stack
для создания строк с одинаковым индексом, когда 50k достигает нескольких раз:
df_join = (df['nb_50'].apply(lambda x: pd.Series(range(x)))
.stack().reset_index(level=1).drop('level_1',1))
df = df.join(df_join).dropna().drop(['nb_50',0],1)
И вы получите ожидаемый результат с вашим примером ввода.
Проблема в том, что когда у вас есть
df= pd.DataFrame({'V1':[180000, 20000, 30000, 50000]})
Мой метод дает вам:
V1
0 180000
0 180000
0 180000
1 20000
3 50000
, и некоторые ошибки могут произойти позже, в то время как когда вы говорите «, когда значение V1 превышает предел 50k, индекс повторяется столько раз, сколько достигается предел, или если значение V1 равнониже предела 50k группирует строки до тех пор, пока предел 50k не будет достигнут или не пройден", и я понимаю, что вы ожидаете:
V1
0 180000
0 180000
0 180000
2 30000
3 50000
В этом случае, если вы не хотите использоватьцикл, когда число превышает 50K, вы можете сделать (примерно то же самоеИдея, чем прежде):
df = df.join(df['V1'].apply(lambda x: pd.Series(range(x/50000)))
.stack().reset_index(level=1).drop('level_1',1)).drop(0,1)
Но я не мог найти простой способ сделать случай, когда число меньше 50 КБ, поэтому ваш цикл for
может быть достаточно.в противном случае, я подумал об этом:
def nb_group_under(v1):
global nb_group
if v1 < 50000:
return nb_group
else:
nb_group += 1
nb_group = 1
df['under_50'] = df['V1'].apply(nb_group_under)
затем вы пытаетесь найти, где 50k передается в созданной группе:
df['sum_under50'] = (df.groupby('under_50').V1.cumsum()/50000).astype(int)
df['sum_under50'] = df.sum_under50 - (df.groupby('under_50').sum_under50
.shift().fillna(df.sum_under50))
df = (df[(df['sum_under50']>0) | (df['V1'] >= 50000)]
.drop(['under_50', 'sum_under50'],1))
Я не особенно доволен методом длядело до 50, но не мог думать иначе.
Надеюсь, что в любом случае это будет полезно или даст вам некоторые идеи о том, как решить вашу проблему без цикла
РЕДАКТИРОВАТЬ: для более общего решения вы можете создать функцию, возвращающую число раз, которое 50kв значении v1 или сделать частичную сумму, возвращающую 1, когда выше 50k, вам все еще нужна глобальная переменная:
def nb_lim_reached (v1, lim_v1):
global partial_sum
if v1 >= lim_v1:
partial_sum = 0
return pd.np.floor(v1/lim_v1)
else:
partial_sum += v1
if partial_sum >= lim_v1:
partial_sum -= lim_v1
return 1
else:
return 0
Теперь вы можете создать еще один столбец с этой функцией:
v1_lim = 50000
partial_sum = 0
df['nb_lim'] = df['V1'].apply(nb_lim_reached, args=( v1_lim,)).astype(int)
Теперь вы используете ту же идею, что и мое решение reviosu с pd.Series
и stack
:
df = (df.join(df['nb_lim'].apply(lambda nb: pd.Series(range(nb)))
.stack().reset_index(level=1).drop('level_1',1))
.dropna().drop(['nb_lim',0],1))