【问题标题】:Pandas shift based on different values to calculate percentages熊猫根据不同的值移动以计算百分比
【发布时间】:2018-08-10 00:33:45
【问题描述】:

我正在尝试从数据帧计算第一次向下的百分比。

这是数据框

        down  distance
1        1.0      10.0
2        2.0      13.0
3        3.0      15.0
4        3.0      20.0
5        4.0       1.0
6        1.0      10.0
7        2.0       9.0
8        3.0       3.0
9        1.0      10.0

我想计算第一次下降的百分比,这意味着第二次下降,获得的码数百分比是多少。对于第三次下降,第三次的百分比基于第一次。

例如,我想要以下输出。

        down  distance    percentage

1        1.0      10.0    NaN
2        2.0      13.0    (13-10)/13
3        3.0      15.0    (15-10)/15
4        3.0      20.0    (20-10)/20
5        4.0       1.0    (1-10)/20
6        1.0      10.0    NaN       # New calculation
7        2.0       9.0    (9-10)/9
8        3.0       3.0    (3-10)/3
9        1.0      10.0    NaN

谢谢

当前的解决方案都适用于第一个问题。

【问题讨论】:

  • 我觉得有错别字.. 不应该是第 5 行的(1-10)/1 吗?
  • 看起来确实是个错字。

标签: python pandas dataframe


【解决方案1】:

这是一个矢量化的解决方案:

# define condition
cond = df['down'] == 1

# calculate value to subtract
first = df['distance'].where(cond).ffill().mask(cond)

# perform calculation
df['percentage'] = (df['distance'] - first) / df['distance']

print(df)

   down  distance  percentage
1   1.0      10.0         NaN
2   2.0      13.0    0.230769
3   3.0      15.0    0.333333
4   3.0      20.0    0.500000
5   4.0       1.0   -9.000000
6   1.0      10.0         NaN
7   2.0       9.0   -0.111111
8   3.0       3.0   -2.333333
9   1.0      10.0         NaN

【讨论】:

  • 我也在想同样的事情!既是算法,又是美丽的。
【解决方案2】:

使用groupbytransform

s = df.groupby(df.down.eq(1).cumsum()).distance.transform('first')
s = df.distance.sub(s).div(df.distance)
df['percentage'] = s.mask(s.eq(0))

   down  distance  percentage
1   1.0      10.0         NaN
2   2.0      13.0    0.230769
3   3.0      15.0    0.333333
4   3.0      20.0    0.500000
5   4.0       1.0   -9.000000
6   1.0      10.0         NaN
7   2.0       9.0   -0.111111
8   3.0       3.0   -2.333333
9   1.0      10.0         NaN

【讨论】:

  • 谢谢!已经为你 +1 了 :) 我认为 ffill 会比 transform('first') 更快
  • 这是一个可靠的答案!
【解决方案3】:

使用 Numpy 位

应该很活泼!

m = df.down.values == 1                # mask where equal to 1
i = np.flatnonzero(m)                  # positions where equal to 1
d = df.distance.values                 # Numpy array of distances

j = np.diff(np.append(i, len(df)))     # use diff to find distances between
                                       # values equal to 1.  Note that I append
                                       # the length of the df as a terminal value

k = i.repeat(j)                        # I repeat the positions where equal to 1
                                       # a number of times in order to fill in.
p = np.where(m, np.nan, 1 - d[k] / d)  # reduction of % formula while masking

df.assign(percentage=p)

   down  distance  percentage
1   1.0      10.0         NaN
2   2.0      13.0    0.230769
3   3.0      15.0    0.333333
4   3.0      20.0    0.500000
5   4.0       1.0   -9.000000
6   1.0      10.0         NaN
7   2.0       9.0   -0.111111
8   3.0       3.0   -2.333333
9   1.0      10.0         NaN

【讨论】:

    【解决方案4】:

    每次down 等于 1 时,使用 groupby 进行分组,而不是使用所需的计算进行转换。然后您可以找到down 再次为1 的位置,并转换为NaN(因为根据您的示例,那里的计算没有意义):

    df['percentage'] = (df.groupby(df.down.eq(1).cumsum())['distance']
                    .transform(lambda x: (x-x.iloc[0])/x))
    
    
    df.loc[df.down.eq(1),'percentage'] = np.nan
    
    >>> df
       down  distance  percentage
    1   1.0      10.0         NaN
    2   2.0      13.0    0.230769
    3   3.0      15.0    0.333333
    4   3.0      20.0    0.500000
    5   4.0       1.0   -9.000000
    6   1.0      10.0         NaN
    7   2.0       9.0   -0.111111
    8   3.0       3.0   -2.333333
    9   1.0      10.0         NaN
    

    【讨论】:

      猜你喜欢
      • 2021-01-05
      • 2023-01-02
      • 2020-09-21
      • 2020-04-17
      • 1970-01-01
      • 2017-02-15
      • 1970-01-01
      • 2015-10-07
      • 1970-01-01
      相关资源
      最近更新 更多