楼主: rosenbloog
4157 17

[问答] 如何补齐有规律的文本(或数字)序列 [推广有奖]

  • 1关注
  • 8粉丝

已卖:3份资源

讲师

16%

还不是VIP/贵宾

-

威望
0
论坛币
1422 个
通用积分
221.8502
学术水平
24 点
热心指数
29 点
信用等级
16 点
经验
956 点
帖子
315
精华
0
在线时间
366 小时
注册时间
2007-10-24
最后登录
2025-10-4

楼主
rosenbloog 发表于 2016-2-9 13:43:55 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
示范数据如下,原始数据比较大。
x = c("max", "unit", "rate", "max", "unit", "rate", "max", "unit", "rate", "unit", "rate")

我的问题是:知道要循环c("max", "unit", "rate"),如何找出有缺失的组别,例如上面x数据中最后一组少了"max",然后进行补齐呢?注意的是我没有类似group ID的数据列,所有有些常用的方法不能直接用。

我的目的是补齐这个序列,看看缺失哪些,进而知道其他相邻的列缺失的数据。这列相当于我缺失的组ID。

非常感谢!
----------------------------------
借用@jiangbeilu的说法,我有这样一个序列:
1 2 3 /1 2 3/ 1 2   /1 2 3/   2 3/1 2 3/   2  /1 2 3/
我想要把每组都变成 1 2 3,注意没有group ID,但是我每组我知道有2,所以知道总共有多少组。
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:Group Unit Rate 原始数据 非常感谢 如何

沙发
ryoeng 在职认证  发表于 2016-2-9 15:50:18
提示: 作者被禁止或删除 内容自动屏蔽
签名被屏蔽

藤椅
jiangbeilu 学生认证  发表于 2016-2-9 17:12:45
你的问题是不是可以转化成这样的:
1 2 3 /1 2 3/ 1 2 /1 2 3/ 2 3/1 2 3

/代表一组,其中,你是想,如果发现了1 2,也就是第三组,就补成 1 2 NA,的形式吧?
如果是补成3的话,我想只要确定了多少组,然后直接rep(1:3,n)就可以了。

所以,没有这么简单。
2 3这样一组,你是希望补成 1 2 3是吧?不过单独一个 2 3 也可以补成NA 2 NA/NA NA 3的形式,这个样子是两组。
所以还是不那么好操作的。
请把您的问题描述清晰一些好么?
已有 1 人评分经验 收起 理由
李会超 + 60 精彩帖子

总评分: 经验 + 60   查看全部评分

板凳
rosenbloog 发表于 2016-2-9 23:07:56
ryoeng 发表于 2016-2-9 15:50
不大明白楼主的问题,`dplyr::mutate()`应该行吧?
数据里暂时没有可以group_by的变量

报纸
rosenbloog 发表于 2016-2-9 23:08:38
jiangbeilu 发表于 2016-2-9 17:12
你的问题是不是可以转化成这样的:
1 2 3 /1 2 3/ 1 2 /1 2 3/ 2 3/1 2 3
你理解的是对的。我稍微编辑了下我的问题。

地板
jiangbeilu 学生认证  发表于 2016-2-10 16:47:51
那这个问题就很简单了,比如你知道有10组,
只需要:
  1. rep(1:3,10)
复制代码

重复10组这样的向量,就完成了要求了,也无需追究原来序列的缺失问题了。

7
rosenbloog 发表于 2016-2-11 10:17:04
jiangbeilu 发表于 2016-2-10 16:47
那这个问题就很简单了,比如你知道有10组,
只需要:
看来我还是一开始没解释清楚,这个1/2/3对应了其他列的数据,相当于是我的ID,但是不全。

8
foozhencheng 学生认证  发表于 2016-2-11 13:15:13
我觉得jiangbeilu的回答是正确的。你先找出在x中有多少个2(比如有n个),然后rep(1:3, n)即可生成你这个ID序列。

9
cheetahfly 在职认证  发表于 2016-2-11 23:52:22
根据经验,我提供的解决方法肯定不是最优的,因此,权当我在此抛砖引玉把。

我大致猜到楼主的目的,因为楼主相当于ID的那列变量是有规则重复,但不规则缺失的,因此,无法真正发挥ID的作用。我想,如果额外加上一列group.id,标明这行数据属于哪个组,应该可以解决该问题了。比如,最终的效果如下:
a    group.id
max    1
unit    1
rate    1
unit    2
rate    2
max    3
unit    3
unit    4
max    5
unit    5
rate    5
这样子,这两列数据一并作为ID使用,使ID有了唯一性,作用可以发挥出来了。
另外,从上面的数据可以轻易得到,第1、5组数据是全的,第2组数据缺了"max"行,第3组数据缺了"rate"行,第4组数据既缺"max"行,也缺"rate"行,(这样每种缺失情况都包含了,等下的测试基本是该向量重复多次。不过,每组"unit"必不可少,不然问题会复杂很多),这样要补全数据也非常容易。

对于补全group.id,我有两个思路,第一个思路要借用“jiangbeilu”同学给出的:rep(c("max","unit","rate"),5)这个向量,这个向量是理想状态下的ID列,可惜和现有的缺失的dataframe无法一一对应,就好比我们去“配钥匙”,先买一把未挫过的“无齿钥匙”,然后用工具按照现有的钥匙的特征加工过,这把钥匙就能用了。

按第一个思路,首先,我们要根据数据框中的“unit”的数据推断出有多少组,假设为“n”,然后构建一把这样的“原始钥匙”:
  1. key <- data.frame(a = rep(c("max", "unit", "rate"), n), group.id = rep(1:n, each=3))
复制代码
然后,我再用“循环”和“递归”设计一个“配钥匙”的函数,基本思想是逐行检验现有数据和key数据,发现现有数据中没有但key数据框中有的,就丢掉key数据中的该行。函数返回新的key数据框:
  1. duplicate.key <- function(df, v) {  #df指原始钥匙key,v指现有数据中含有"unit"的那一列
  2.   for (i in 1:length(v)) {
  3.     if (df[i, 1] == v[i]) next
  4.     else {
  5.       if (i == 1) {
  6.         df <- duplicate.key(df[-1,], v)
  7.       } else {
  8.         df <- rbind(df[1:(i-1),],
  9.                     duplicate.key(df[(i+1):nrow(df),], v[i:length(v)]))
  10.         return(df)
  11.       }
  12.     }
  13.   }
  14.   df
  15. }
复制代码
测试一下,可用。万事大吉了吗?等等,楼主说过,他的原始数据比较大,因此,我要测试一下这种方法的效率。我用千万行级别的原始数据测试,内存不够;百万级别的,内存不够;十万级别的,告知递归得太深了;万级别的,还是递归得太深了;千行级别的,通过,但在我的老电脑上耗时大概10秒以上。

这样显然不行,这个思路不实用。当然,如果不用递归,而用更加复杂一些的循环方法,应该可以使数据处理的上限提高1到2个数量级,但仍无法改变其内存和CPU利用低效的事实。

第二个思路是“向量化”的处理方法。比如,我用下面的自编函数,arguments是现有数据框,和c("max", "unit", "rate")向量,函数返回的是加了group.id列后的现有数据框:
  1. add.group.id <- function(df, v) { #df是现有数据框,第一列是含有“unit”的那一列,v是c("max", "unit", "rate")向量
  2.   group.num <- sum(df[,1] == v[2])
  3.   row.num <- nrow(df)
  4.   group.id <- vector(length = row.num)
  5.   pos.2 <- (1:row.num)[df[,1] == v[2]]
  6.   group.id[pos.2] <- 1:group.num
  7.   pos.1 <- pos.2 - 1
  8.   val.1 <- (1:group.num)[df[pos.1, 1] == v[1]]
  9.   pos.1 <- pos.1[df[pos.1, 1] == v[1]]
  10.   pos.3 <- pos.2 + 1
  11.   val.3 <- (1:group.num)[df[pos.3, 1] == v[3]]  
  12.   pos.3 <- pos.3[df[pos.3, 1] == v[3]]
  13.   group.id[pos.1] <- val.1
  14.   group.id[pos.3] <- val.3
  15.   df$group.id <- group.id
  16.   df
  17. }
复制代码
我测试过,可以运行1千万行以上的数据(当然,我的模拟数据中其他列数据不复杂),耗时5秒多,比第一个思路处理1千多行的数据还要快得多。

重要提醒:两个思路都假定头尾数据是完整的,因为头尾数据的判断和补全很容易,因此,未对头尾组缺失的情况进行容错设计。

通过这个案例,我自己也深刻地体会了R语言的长处和短处,如果用直观的方法,利用循环和递归,编程效率高,但执行效率太差;如果用向量化的方法去编程,思考的过程耗时比较长,但执行起来简直云泥之别,这可能就是R语言独特的魅力所在吧!

10
czrdiao 发表于 2016-2-12 08:48:28
如果真的是cheetahfly说的,我这个方法好像比较简单
x = c("max", "unit", "rate", "max", "unit", "rate", "max", "unit", "rate", "unit", "rate")
id <- c("max", "unit", "rate")
ord <- match(x, id)
di <- diff(match(x, id))##the negative value is the next group
ord2 <- which(di<=0)
rep(1:(length(ord2)+1), time = c(ord2[1], diff(ord2), length(x)-ord2[length(ord2)]))
我就不解释了,都是简单的函数,运行一下就看懂了!

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

本版微信群
加好友,备注cda
拉您进交流群
GMT+8, 2025-12-29 01:38