#python #pandas #dataframe
#python #pandas #dataframe
Вопрос:
У меня есть фрейм данных, как показано ниже:
data = {'sid':[1,1,1,2,2,2],
'field1':['start', None, None, 'start', None, None],
'field2':['a', 'b', 'z', 'd', 'z','s'],
'val':[20, 22, 23, 40, 45, 47]}
df = pd.DataFrame(data)
print(df)
sid field1 val
0 1 start 20
1 1 None 22
2 1 None 23
3 2 start 40
4 2 None 45
5 2 None 47
Я хотел бы создать новое поле newval, в котором хранится разница между значением val этой строки и значением val в строке с тем же sid и field1 = ‘start’ .
sid field1 val newval
0 1 start 20 NaN
1 1 None 22 2.0
2 1 None 23 3.0
3 2 start 40 NaN
4 2 None 45 5.0
5 2 None 47 7.0
Я пробовал diff() с помощью groupby(), но это дает мне большую разницу.
df['newval'] = df.groupby('sid')['val'].diff()
sid field1 val newval
0 1 start 20 NaN
1 1 None 22 2.0
2 1 None 23 1.0
3 2 start 40 NaN
4 2 None 45 5.0
5 2 None 47 2.0
Как я могу получить разницу из конкретной строки?
Ответ №1:
Вы можете использовать groupby со вспомогательным столбцом, sid
а затем получить первое значение группы, а затем вычесть из val
поля.
df['new_val'] = (df['val']-
df.groupby(['sid',df['field1'].eq("start").cumsum()])['val'].transform("first"))
print(df)
sid field1 field2 val new_val
0 1 start a 20 0
1 1 None b 22 2
2 1 None z 23 3
3 2 start d 40 0
4 2 None z 45 5
5 2 None s 47 7
Вспомогательный столбец, как показано ниже, что помогает в группировке:
print(df['field1'].eq("start").cumsum())
0 1
1 1
2 1
3 2
4 2
5 2
Name: field1, dtype: int32
Комментарии:
1. В самом общем случае, когда в каждом идентификаторе есть несколько запусков и данные не отсортированы по идентификатору, это может привести к сбою.
Ответ №2:
Вероятно, не самое элегантное решение, но вы могли бы объединить только строки с field1 = 'start'
Использование df
, как определено выше:
tmp = pd.merge(df, df.loc[df['field1'] == 'start', ['sid', 'val']],
how = 'left', left_on = 'sid', right_on = 'sid',
suffixes = ['', 'start_val'])
tmp['newval'] = np.where(tmp['field1'] == 'start', np.nan, tmp['val'] - tmp['valstart_val'])
tmp.drop('valstart_val', axis = 1, inplace = True)
Вывод:
sid field1 field2 val newval
1 start a 20 NaN
1 None b 22 2.0
1 None z 23 3.0
2 start d 40 NaN
2 None z 45 5.0
2 None s 47 7.0
Комментарии:
1. Мне нравится решение anky
2. К вашему сведению, существует
pandas.DataFrame.where
иpd.NA
, который устраняет необходимость импортаnumpy
.
Ответ №3:
Похоже, ваши данные уже отсортированы, sid
и start
в первой строке каждого идентификатора есть только один. В этом случае вы можете сделать:
ids = df.duplicated(['sid'])
# also
# ids = df['field1'].astype(bool)
df['newval'] = df['val'].sub(df['val'].mask(ids).ffill()).where(ids)
Вывод:
sid field1 field2 val newval
0 1 start a 20 NaN
1 1 None b 22 2.0
2 1 None z 23 3.0
3 2 start d 40 NaN
4 2 None z 45 5.0
5 2 None s 47 7.0