【问题标题】:How can I calculate values specific to an ID provided on each line?如何计算特定于每行提供的 ID 的值?
【发布时间】:2016-05-11 20:53:42
【问题描述】:

我有一个如下所示的值数据表:

Score ID
1.2    1
2.4    1
1.1    1
1.9    1
2.4    2
3.5    2
2.2    2
1.1    3
1.1    3
1.7    3
3.1    3
2.2    3

而我真正需要的是在单独的列中计算每个 ID 的分数变化,如下所示:

Score   ID  Changes
1.2     1   
2.4     1   1.2
1.1     1   -1.3
1.9     1   0.8
2.4     2   
3.5     2   1.1
2.2     2   -1.3
1.1     3   
1.1     3   0
1.7     3   0.6
3.1     3   1.4
2.2     3   -0.9

注意每个“变化”是如何通过获取先前的分数并从当前分数中减去来计算的:例如在第一次更改中,通过 1.2 = 2.4(当前分数)- 1.2(上一个分数)得到 1.2

问题是这些分数只能与 ID 范围内的分数相关。您不能只是迭代并获取分数的差异。我该怎么做?我可以使用什么逻辑来测试在同一 ID 中包含“更改”?我熟悉 R 或 python(或 BASH)来执行此操作。

【问题讨论】:

  • 向我们展示您的尝试。
  • 如果分数真的像这样,那么你当然可以遍历它们,只需添加一个 if 语句来检查之前的 ID 是否相同。

标签: python r pandas


【解决方案1】:

在 R 中可能:

transform(
  df, 
  Changes = ave(df$Score, df$ID, FUN = function(x) c(NA, diff(x)))
)
#    Score ID Changes
# 1    1.2  1      NA
# 2    2.4  1     1.2
# 3    1.1  1    -1.3
# 4    1.9  1     0.8
# 5    2.4  2      NA
# 6    3.5  2     1.1
# 7    2.2  2    -1.3
# 8    1.1  3      NA
# 9    1.1  3     0.0
# 10   1.7  3     0.6
# 11   3.1  3     1.4
# 12   2.2  3    -0.9

df 保存您的原始数据框。


关于@Bulat 的评论:

id<- c(1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3)
score <-  c(1.2, 2.4, 1.1, 1.9, 2.4, 3.5, 2.2, 1.1, 1.1, 1.7, 3.1, 2.2)
library(data.table)
df <- data.frame(id, score)
dt = data.table(id, score)
library(microbenchmark)
microbenchmark(
  dt = dt[ , diff := c(NA, diff(score)), by = id],
  df = df$diff <- ave(df$score, df$id, FUN = function(x) c(NA, diff(x))),
  times = 1000
)
# Unit: microseconds
#  expr      min        lq      mean    median        uq      max neval cld
#    dt 1121.931 1225.2660 1342.4626 1269.5530 1321.2210 5908.411  1000   b
#    df  397.175  488.2085  547.8198  525.8175  586.7995 7784.270  1000  a 

【讨论】:

  • 我不确定我是否理解更改行中发生的情况。你能解释一下吗?它如何知道按 ID 分组?那个 x 是从哪里来的?
  • 看看?ave:第一个参数后面的参数可能是分组变量,这里是df$IDx 来自 function 调用。 ave 基本上将数据按ID 拆分,将Score 作为x 传递给函数,然后计算连续差异并添加NA,因为第一个值没有差异。也可能是df$Changes &lt;- ave(df$Score, df$ID, FUN = function(x) c(NA, diff(x)))
  • 这似乎很慢,考虑到语法的复杂性,我不会这样做。
  • @Bulat ave 确实很快 - 请参阅我的编辑。而且它不需要另一个包和数据结构。
  • 你只测试了 10 条记录吗?
【解决方案2】:

在 Python 中使用 Pandas:

import pandas as pd

df = pd.DataFrame(
        {'ID': [1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3],
         'Score': [1.2, 2.4, 1.1, 1.9, 2.4, 3.5, 2.2, 1.1, 1.1, 1.7, 3.1, 2.2]})

df['Changes'] = df.groupby('ID').Score.transform(lambda group: group.diff())

>>> df
    Score  ID  Changes
0     1.2   1      NaN
1     2.4   1      1.2
2     1.1   1     -1.3
3     1.9   1      0.8
4     2.4   2      NaN
5     3.5   2      1.1
6     2.2   2     -1.3
7     1.1   3      NaN
8     1.1   3      0.0
9     1.7   3      0.6
10    3.1   3      1.4
11    2.2   3     -0.9

【讨论】:

  • 哇,这很整洁。我不知道在 python 中有一个特定的命令 df 可以做到这一点
【解决方案3】:

R 与data.table:

id<- c(1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3)
score <-  c(1.2, 2.4, 1.1, 1.9, 2.4, 3.5, 2.2, 1.1, 1.1, 1.7, 3.1, 2.2)
library(data.table)
df = data.table(id, score)

df[ , diff := c(NA, diff(score)), by = id]

值得一提的是,这比 transform 方法快了 10 倍:

id<- c(1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3)
id <- rep(id, 10^5)
score <-  c(1.2, 2.4, 1.1, 1.9, 2.4, 3.5, 2.2, 1.1, 1.1, 1.7, 3.1, 2.2)
score <- rep(score, 10^5)
library(data.table)
dt = data.table(id, score)
df = data.frame(id, score)

library(microbenchmark)
m <- microbenchmark(
  "data.table" = dt[ , diff := c(NA, diff(score)), by = id],
  "transform" = transform(
    df, 
    Changes = ave(df$score, df$id, FUN = function(x) c(NA, diff(x)))
  ), times = 10
)

boxplot(m)
print(m)
# Unit: milliseconds
#      expr       min        lq      mean    median        uq       max neval
# data.table   95.1905  100.3342  111.2434  102.6525  106.7417  151.2913    10
#  transform 1032.3829 1066.3912 1078.5727 1070.9577 1103.4971 1135.7380    10

【讨论】:

    【解决方案4】:

    R 中使用dplyr

    library(dplyr)
    df1 %>% 
       group_by(ID) %>% 
       mutate(diff = c(NA, diff(Score)))
    #   Score    ID  diff
    #   <dbl> <int> <dbl>
    #1    1.2     1    NA
    #2    2.4     1   1.2
    #3    1.1     1  -1.3
    #4    1.9     1   0.8
    #5    2.4     2    NA
    #6    3.5     2   1.1
    #7    2.2     2  -1.3
    #8    1.1     3    NA
    #9    1.1     3   0.0
    #10   1.7     3   0.6
    #11   3.1     3   1.4
    #12   2.2     3  -0.9
    

    【讨论】:

      猜你喜欢
      • 2020-01-15
      • 2023-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多