簡體   English   中英

從 pandas dataframe 中同一字段的所有其他行中減去一行字段中的值

[英]Subtract the value in a field in one row from all other rows of the same field in pandas dataframe

我有一個 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與具有相同sidfield1 = 'start' 的行中的val之間的差異。

   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

我已經嘗試使用 groupby() 進行 diff() 但這給了我一個運行差異。

 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

如何從特定行中獲得差異?

您可以將 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

可能不是最優雅的解決方案,但您可以僅使用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)

Output:

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

看起來您的數據已經按sid排序,並且每個 Id 的第一行只有一個start 在這種情況下,您可以這樣做:

ids = df.duplicated(['sid'])
# also
# ids = df['field1'].astype(bool)

df['newval'] = df['val'].sub(df['val'].mask(ids).ffill()).where(ids)

Output:

   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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM