вам нужно использовать groupby
для столбца 'условие' и cumcount
, чтобы подсчитать, сколько идентификаторов в каждом условии до текущей строки (что, по-видимому, и делает ваш код):
df['count'] = df.groupby('condition').cumcount()+1 # +1 is to start at 1 not 0
с вашим входным образцом, вы получите:
id condition count
0 1234 A 1
1 2323 B 1
2 3843 B 2
3 1234 C 1
4 8574 A 2
5 9483 A 3
, что быстрее, чем при использовании цикла for
и, если вы хотите, например, иметь строку с условием A, вы можете использовать маску, например, если вы делаете
print (df[df['condition'] == 'A'])
, вы видите строку с условием egal для A. Итак, чтобы получить массив,
arr_A = df.loc[df['condition'] == 'A','id'].values
print (arr_A)
array([1234, 8574, 9483])
РЕДАКТИРОВАТЬ: чтобы создать два столбца для условий, вы можете сделать, например, для условия A:
# put 1 in a column where the condition is met
df['nb_cond_A'] = pd.np.where(df['condition'] == 'A',1,None)
# then use cumsum for increment number, ffill to fill the same number down
# where the condition is not meet, fillna(0) for filling other missing values
df['nb_cond_A'] = df['nb_cond_A'].cumsum().ffill().fillna(0).astype(int)
# for the partial list, first create the full array
arr_A = df.loc[df['condition'] == 'A','id'].values
# create the column with apply (here another might exist, but it's one way)
df['partial_arr_A'] = df['nb_cond_A'].apply(lambda x: arr_A[:x])
вывод выглядит так:
id condition nb_condition_A partial_arr_A nb_cond_A
0 1234 A 1 [1234] 1
1 2323 B 1 [1234] 1
2 3843 B 1 [1234] 1
3 1234 C 1 [1234] 1
4 8574 A 2 [1234, 8574] 2
5 9483 A 3 [1234, 8574, 9483] 3
то же самое для B, C. Может быть с циклом for cond in set(df['condition'])
может быть полезно для обобщения
РЕДАКТИРОВАТЬ 2: одна идея сделать то, что вы пояснили в комментариях, но не уверены, что это улучшает производительность:
# array of unique condition
arr_cond = df.condition.unique()
#use apply to create row-wise the list of ids for each condition
df[arr_cond] = (df.apply(lambda row: (df.loc[:row.name].drop_duplicates('id','last')
.groupby('condition').id.apply(list)) ,axis=1)
.applymap(lambda x: [] if not isinstance(x,list) else x))
Некоторые пояснения: для каждой строки выберите кадр данных до этой строки loc[:row.name]
, отбросьте дублированный «id» и оставьте последний drop_duplicates('id','last')
(в вашем примере это означает, что как только мы достигнем строки 3, строка 0 удаляется, так как идентификатор 1234 удваивается), затем данные группируются по условию groupby('condition')
, и идентификаторы для каждого условия помещаются в один и тот же список id.apply(list)
. Часть, начинающаяся с applymap
fillna с пустым списком (вы не можете использовать fillna ([]), это невозможно).
Для длины для каждого условия вы можете сделать:
for cond in arr_cond:
df['len_{}'.format(cond)] = df[cond].str.len().fillna(0).astype(int)
Результат такой:
id condition A B C len_A len_B len_C
0 1234 A [1234] [] [] 1 0 0
1 2323 B [1234] [2323] [] 1 1 0
2 3843 B [1234] [2323, 3843] [] 1 2 0
3 1234 C [] [2323, 3843] [1234] 0 2 1
4 8574 A [8574] [2323, 3843] [1234] 1 2 1
5 9483 A [8574, 9483] [2323, 3843] [1234] 2 2 1