【问题标题】:Calculate Percent-Change (over time) of pandas column values based on other column value根据其他列值计算熊猫列值的百分比变化(随时间变化)
【发布时间】:2019-06-13 14:42:51
【问题描述】:

我正在使用示例数据集:

       date      name     point
0   4/24/2019   Martha   3617138
1   4/25/2019   Martha   3961918
2   4/26/2019   Martha   4774966
3   4/27/2019   Martha   5217946
4   4/24/2019   Alex     62700321
5   4/25/2019   Alex     66721020
6   4/26/2019   Alex     71745138
7   4/27/2019   Alex     88762943
8   4/28/2019   Alex    102772578
9   4/29/2019   Alex    129089274
10  3/1/2019    Josh     1063259
11  3/3/2019    Josh     1063259
12  3/4/2019    Josh     1063259
13  3/5/2019    Josh     1063259
14  3/6/2019    Josh     1063259

以及名称值列表

nameslist = ['Martha', 'Alex', 'Josh']

我想根据名称列中的标识符计算所有行的百分比变化。

预期输出:

name    percent change
Martha      30.7
Alex        51.4
Josh          0

我最初尝试遍历我的列表和表格,并添加与列表值匹配的所有行,附加一个带有更改计算的列表,然后移动我的列表的下一个值,但我无法表达我的正确编码以实现这一目标。

df['date'] = pd.to_datetime(df['date'])
df = df.sort_values(by='date')

growthlist=[]
temptable=[]
for i in nameslist:
    for j in df:
        temptable.append(df[df['name'].str.match(nameslist[i])])
        length=[]
        growth=temptable[0]-temptable[length-1]
        growthlist.append(i,growth)

但这会产生错误:

TypeError: list indices must be integers or slices, not str

我也不介意使用 .groupby() 和 .pct_change() 来实现这个目标,但是

growth = df.groupby('name').pct_change()

生成一个以以下结尾的长回溯:

TypeError: unsupported operand type(s) for /: 'str' and 'float'

最后,我想将它嵌套在一个函数中,这样我就可以在其他数据集上使用它并能够选择我的列名(我正在使用的实际数据集没有标准化,因此目标列名通常不同)

def calc_growth(dataset,colname):

但我不确定这个问题是否太过分了。

不幸的是,我对这个问题很迷茫,所以任何帮助都将不胜感激。我也想知道转换是否是一种更简单的方法,因为至少我总是知道我需要计算的两个数字的确切位置,但我什至不知道我将如何开始这样的事情。

谢谢

【问题讨论】:

  • df.groupby('name').point.pct_change()?
  • 你能详细说明你是如何聚合的吗?
  • @QuangHoang 如果真的那么容易,我会很沮丧。在我的实际数据集中,计算增长的列实际上是“l.row_cnt”,那么我该如何重新格式化来测试呢?
  • @yatu 我不确定我是否理解你的问题。 “如何”我正在聚合使用“growth = df.groupby('name').pct_change()”,但我不确定如何扩展命令以实际计算 'point' 列中的变化(col我的实际数据集中的名称是'l.row_cnt')
  • 我第二个@yatu,你能解释一下你的预期输出吗?

标签: python pandas dataframe pandas-groupby


【解决方案1】:

您可以使用apply 与通过.values 接近的lastfirst 值来计算整个组的百分比变化:

df.groupby('name',sort=False).apply(lambda x: (x['point'].values[-1] - x['point'].values[0]) / x['point'].values[-1] * 100)\
    .reset_index(name='pct change')

     name               pct change
0  Martha  30.67889165583545363347
1    Alex  51.42871358932579539669
2    Josh   0.00000000000000000000

说明

首先我们在 name 上使用 groupby,它会根据每个唯一名称为我们提供一个组(读取:一个数据框):

for _, d in df.groupby('name', sort=False):
    print(d, '\n')

        date    name    point
0 2019-04-24  Martha  3617138
1 2019-04-25  Martha  3961918
2 2019-04-26  Martha  4774966
3 2019-04-27  Martha  5217946 

        date  name      point
4 2019-04-24  Alex   62700321
5 2019-04-25  Alex   66721020
6 2019-04-26  Alex   71745138
7 2019-04-27  Alex   88762943
8 2019-04-28  Alex  102772578
9 2019-04-29  Alex  129089274 

         date  name    point
10 2019-03-01  Josh  1063259
11 2019-03-03  Josh  1063259
12 2019-03-04  Josh  1063259
13 2019-03-05  Josh  1063259
14 2019-03-06  Josh  1063259 

然后我们将我们自己制作的lambda 函数应用到每个单独的组 并应用以下计算:

百分比变化 =(点最后一个值 - 点第一个值)/点最后一个值 * 100


然后我们使用reset_index 将我们的name 列从索引中取出,因为groupby 将它作为索引。

【讨论】:

  • 这适用于我的测试数据集和真实数据集。我会将其标记为正确答案。我不想打扰你,但你介意分解这段代码的算法吗?我很难理解它,但在我的新角色中我会经常做这些类型的任务,所以我希望以后能够复制它
  • 完美。注意:我编辑了* 100 以获得您想要的输出@NickBohl
  • @efran 我不想打扰,但我实际上正在寻找“百分比变化 =(最后一个值 - 第一个值)/最后一个值 *100”我们正在寻找它有多少随着时间的推移而改变,而不仅仅是多少。已按日期对数据集进行排序,以确保该表按时间顺序准确。抱歉,我应该更具体地回答我的问题
  • 不用担心,我会查看并相应地编辑我的答案@NickBohl
  • 谢谢@erfan。有趣的是,输出是相同的,即使是我的真实数据集。根据我观察到的关于我正在跟踪的表的行为,我很惊讶这两种方法产生了相同的结果,但是通过你的解释,我确信数学是合理的。非常感谢您的帮助!
【解决方案2】:

假设有第四列,也许描述如下,

       date      name     point      descr
0   4/24/2019   Martha   3617138      12g of ecg
1   4/25/2019   Martha   3961918      12g of eg
2   4/26/2019   Martha   4774966      43m of grams
3   4/27/2019   Martha   5217946      13cm of dose
4   4/24/2019   Alex     62700321     32m of grams
5   4/25/2019   Alex     66721020     12g of egc
6   4/26/2019   Alex     71745138      43m of grams
7   4/27/2019   Alex     88762943      30cm of dose
8   4/28/2019   Alex    102772578      12g of egc
9   4/29/2019   Alex    129089274      43m of grams
10  3/1/2019    Josh     1063259       13cm of dose
11  3/3/2019    Josh     1063259       12g of eg
12  3/4/2019    Josh     1063259       12g of eg
13  3/5/2019    Josh     1063259       43m of grams   
14  3/6/2019    Josh     1063259       43m of grams

你能把代码改写成

df.groupby('name',sort=False).orderby('descr').apply(lambda x: (x['point'].values[-1] - x['point'].values[0]) / x['point'].values[-1] * 100)\
    .reset_index(name='pct change')\.reset_index(name='descr')

或者您认为合并描述列的正确方法是什么?

【讨论】:

    猜你喜欢
    • 2023-01-02
    • 1970-01-01
    • 1970-01-01
    • 2022-11-19
    • 1970-01-01
    • 1970-01-01
    • 2016-05-07
    • 1970-01-01
    • 2019-01-26
    相关资源
    最近更新 更多