楼主: wx2123
9207 17

[问答] R语言数据处理的问题 [推广有奖]

11
abelus 发表于 2022-3-2 14:48:11
wx2123 发表于 2022-2-26 13:33
你说的对,我也在探索x移动的规则。而且我可能在误导你,因为我自己说的也不一定对。
这个问题可能没有那 ...
id = 1 的最后一行的x为啥要取值41, 而不是26?
感觉和描述的要求不一致啊。

id = 2 的描述就完全容易推导出到底x列是怎么通过s求出来的了。

每个单元格,用数学公式给表示下会不会更好点。

12
正直者之死 发表于 2022-3-2 16:02:45
R实现
  1. #! r
  2. df1 <- data.frame(id = c(rep(1, 7), rep(2, 7)), t = c(1:7, 1:7), dm = c(rep(1, 7), rep(2, 2), rep(3, 5)), s = c(15, 16, 77, 80, 97, 26, 15, 4, 8, 3, 5, 45, 85, 35))

  3. df1$x <- rep(0, nrow(df1))

  4. for (i in 1:nrow(df1)){
  5.     id <- df1$id[i]
  6.     dm <- df1$dm[i]
  7.     s <- df1$s[i]
  8.     to_i <- i + dm
  9.     if (to_i <= nrow(df1) && id == df1$id[to_i]){
  10.         df1$x[to_i] <- s
  11.     }
  12. }
复制代码

py实现
  1. #! py
  2. from pandas import DataFrame as DF

  3. df1 = DF({'id': [1 for i in range(7)] + [2 for i in range(7)], 't': [1 for i in range(14)], 'dm': [1 for i in range(7)] + [2, 2] + [3 for i in range(5)], 's': [15, 16, 77, 80, 97, 26, 15, 4, 8, 3, 5, 45, 85, 35]})

  4. df1['x'] = [0 for i in range(len(df1))]

  5. for i in range(len(df1)):
  6.     id = df1['id'][i]
  7.     dm = df1['dm'][i]
  8.     s = df1['s'][i]
  9.     to_i = i + dm
  10.     if to_i < len(df1) and id == df1['id'][to_i]:
  11.         df1['x'][to_i] = s
复制代码

无标题py.png (89.26 KB)

无标题py.png

无标题.png (62.72 KB)

无标题.png

已有 1 人评分学术水平 热心指数 信用等级 收起 理由
Sunknownay + 3 + 3 + 3 热心帮助其他会员

总评分: 学术水平 + 3  热心指数 + 3  信用等级 + 3   查看全部评分

13
wx2123 在职认证  发表于 2022-3-2 23:43:07
正直者之死 发表于 2022-3-2 16:02
R实现

py实现
非常感谢。我想在进一步问一下。
如果x的值在某id的最后一行是若干行s加和而成,如何计算。
用sas程序可以这样表达。这里last.id是sas找最后一行的办法。找打最后一行以后,对dc(其实就是s)循环n次加和,得到最后一行的x。

如果不是最后一行,x就是dc[t]。这个就是我上面问过的情况,你已经解决了。

loop.png




x的计算包括两种情况:

1. 不是某id的最后一行,x的值就根据dm的数值移动s。例如,
id = 1, dm = 1, s的第一行为15,而x的第二行为15。
不过id = 2时,dm的值有两个(1和2),所以移动的情况又会复杂一些。

2. 某id的最后一行,则要根据t和dm的值,计算x。比方说,
id = 1时,最后1行的t = 7,dm = 1。那么t - dm = 6。然后就从s的第6行开始累加。x = 26 + 15 = 41。
id = 2时,最后1行的t = 7,dm = 2。那么t - dm = 5。然后就从s的第6行开始累加。x = 45 + 85 + 35 = 165。
(不过这里面还有n的问题,这里n=3,所以最多加3个数。)


输出结果为
output.png


详情见我的另一个帖子:
请教SAS中的数组和循环如何在R语言中实现 - R语言论坛 - 经管之家(原人大经济论坛) (pinggu.org)


output.png (11.88 KB)

output.png

14
正直者之死 发表于 2022-3-3 10:23:36
wx2123 发表于 2022-3-2 23:43
非常感谢。我想在进一步问一下。
如果x的值在某id的最后一行是若干行s加和而成,如何计算。
用sas程序可 ...
之前处理的逻辑不变,仅作添加部分(图就不贴了)
  1. #! r
  2. df <- data.frame(id = c(rep(1, 7), rep(2, 7)), t = c(rep(1:7, 2)), dm = c(rep(1, 9), rep(2, 5)), s = c(15, 66, 77, 80, 97, 26, 15, 4, 8, 3, 5, 45, 85, 35))

  3. df$x <- rep(0, nrow(df))

  4. for (i in 1:nrow(df)){
  5.     id <- df$id[i]
  6.     dm <- df$dm[i]
  7.     s <- df$s[i]
  8.     to_i <- i + dm
  9.     if (to_i <= nrow(df) && id == df$id[to_i]){
  10.         df$x[to_i] <- s
  11.     }
  12. }

  13. # 序号去重
  14. id_set <- unique(df$id)

  15. for (i in 1:length(id_set)){
  16.     # 定位最后一行
  17.     last_index <- max(which(df$id == id_set[i]))
  18.     # 注意这里默认根据dm前推行id均一致,否则同样需要类似定位first_index并添加相关逻辑
  19.     # 代码块解析问题,这里拆成多行写了
  20.     start_index <- last_index - df$dm[last_index]
  21.     sum_value <- sum(df$s[start_index:last_index])
  22.     df$x[last_index] <- sum_value
  23. }
复制代码

15
wx2123 在职认证  发表于 2022-3-3 11:35:27
正直者之死 发表于 2022-3-3 10:23
之前处理的逻辑不变,仅作添加部分(图就不贴了)
非常感谢。新的代码我在研究一下。

有个情况我想说一下。第一个For循环在真实的数据中需要时间比较长,50万行的数据大约需要半个小时。不过结果是对的。

我之前一直想避免使用循环,想用left_join()函数,但没有搞定。遇到的问题同一个id里面dm有不同的值,join出来有些问题。

所以还想请教一下,能不能避免使用循环,提高计算速度。谢谢!

16
正直者之死 发表于 2022-3-3 13:33:39
wx2123 发表于 2022-3-3 11:35
非常感谢。新的代码我在研究一下。

有个情况我想说一下。第一个For循环在真实的数据中需要时间比较长, ...
第一部分试下用这个,可能会快点
  1. df <- data.frame(id = c(rep(1, 7), rep(2, 7)), t = c(rep(1:7, 2)), dm = c(rep(1, 9), rep(2, 5)), s = c(15, 66, 77, 80, 97, 26, 15, 4, 8, 3, 5, 45, 85, 35))

  2. lag <- function(i){
  3.     # s的i步滞后
  4.     s_lag <- c(rep(0, i), df$s[1:(nrow(df) - i)])
  5.     # id的i步滞后
  6.     id_lag <- c(rep(0, i), df$id[1:(nrow(df) - i)])
  7.     # dm的i步滞后
  8.     dm_lag <- c(rep(0, i), df$dm[1:(nrow(df) - i)])
  9.     # 滞后前后id是否相等
  10.     id_eq <- (id_lag == df$id)
  11.     # 滞后dm是否对应
  12.     dm_eq <- (dm_lag == i)
  13.     # 返回滞后前与滞后后id相等的s滞后
  14.     return (s_lag * id_eq * dm_eq)
  15. }

  16. # 构造dm集合
  17. dm_set <- unique(df$dm)

  18. df$x <- 0

  19. for (i in 1:length(dm_set)){
  20.     # 代码块解析问题,拆成了2行,实现df$x += lag(dm_set[i])
  21.     tmp <- df$x
  22.     df$x <- tmp + lag(dm_set[i])
  23. }
复制代码


17
wx2123 在职认证  发表于 2022-3-5 11:13:53
正直者之死 发表于 2022-3-3 13:33
第一部分试下用这个,可能会快点
这种方法大幅提高了计算速度!
太厉害了!

18
wx2123 在职认证  发表于 2022-3-16 04:58:45
正直者之死 发表于 2022-3-3 10:23
之前处理的逻辑不变,仅作添加部分(图就不贴了)
我又发现计算最后一行x的一个新问题。
计算最后一行

如上图,当id = 2时,如果dm有4个2和3个3,那么最后一行的x值应该是165。也就是dm = 3对应s全部值的和(45 + 85 + 35 = 165)。 而如果按照目前的算法,结果是170。也就是多加了第11行的5。

所以我觉得应该把start_index改一下。我的思路是加一个min()函数,确保不要把dm = 2的值加进来。

用程序表达如下:
start_index <- last_index - min(xxx, df$dm[last_index])
对于id = 2的情况,xxx应该是2。但是我也没有想出来什么算法能根据条件确定start_index。

或者你有什么更好的方法。
再次请教,谢谢!

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群
GMT+8, 2026-1-9 11:36