问题 确定data.frame的列何时更改值并返回更改的索引


我试图找到一种方法来确定一组列何时更改data.frame中的值。让我直截了当,请考虑以下示例:

x<-data.frame(cnt=1:10, code=rep('ELEMENT 1',10), val0=rep(5,10), val1=rep(6,10),val2=rep(3,10))
x[4,]$val0=6
  • cnt列是一个唯一的ID(可以是日期或时间列,为简单起见,这里是一个int)
  • 代码列就像行集的代码(想象几个这样的组,但代码不同)。代码和cnt是我的data.table中的键。
  • val0,val1,val2列就像得分一样。

上面的data.frame应该被理解为:'ELEMENT 1'的分数从5,6,3开始,一直保持到4迭代时它们变为6,6,3,然后变回5,6 ,3。

我的问题是,有办法获得 第1,第4和第5 data.frame的一行?有没有办法检测列何时发生变化? (btw有12列)

我试过用了 复制 data.table(在大多数情况下完美地工作)但在这种情况下它将删除所有重复项并仅保留第1行和第4行(删除第5行)。

你有什么建议吗?我宁愿不使用for循环,因为有大约。 2M行。


10099
2018-01-21 18:15


起源



答案:


data.table 版本1.8.10(CRAN中的稳定版本),有一个(n)(未导出的)函数调用 duplist 这正是这样做的。它也是用C语言编写的,因此速度非常快。

require(data.table) # 1.8.10
data.table:::duplist(x[, 3:5]) 
# [1] 1 4 5

如果您正在使用的开发版本 data.table (1.8.11),然后有一个更高效的版本(在内存方面)重命名为 uniqlist,这完全相同的工作。可能这应该导出到下一个版本。似乎不止一次出现过SO。让我们来看看。

require(data.table) # 1.8.11
data.table:::uniqlist(x[, 3:5])
# [1] 1 4 5

12
2018-01-21 20:00



+1我不知道这些功能。 - Sven Hohenstein
他是阿伦,很棒。我使用data.table几乎完全是为了诚实。如果你不介意,还有一个问题。当我运行data.frame :: duplist时,我得到一个错误[...]不是类型列表。参数不应该是data.table?只是为了澄清,这正是我正在寻找的功能。一旦我对你的问题发表评论,我会接受这个答案。谢谢 - Nikos
尼科斯, uniqlist/duplist 是一个功能 data.table 包。因为它没有导出,你将不得不使用 data.table::: (在哪里 data.table 这里指的是包)运算符来访问该函数。它基本上可以在data.frames / data.tables上运行(因为它需要列表输入)。希望这可以解决问题吗? - Arun
当然。它基本上为您提供每个独特组合的索引。更像 rle,但使用列表,但返回索引而不是值。 - Arun
我才意识到你是一个 data.table 开发者 - 难怪! 提交的问题。 - Heisenberg


答案:


data.table 版本1.8.10(CRAN中的稳定版本),有一个(n)(未导出的)函数调用 duplist 这正是这样做的。它也是用C语言编写的,因此速度非常快。

require(data.table) # 1.8.10
data.table:::duplist(x[, 3:5]) 
# [1] 1 4 5

如果您正在使用的开发版本 data.table (1.8.11),然后有一个更高效的版本(在内存方面)重命名为 uniqlist,这完全相同的工作。可能这应该导出到下一个版本。似乎不止一次出现过SO。让我们来看看。

require(data.table) # 1.8.11
data.table:::uniqlist(x[, 3:5])
# [1] 1 4 5

12
2018-01-21 20:00



+1我不知道这些功能。 - Sven Hohenstein
他是阿伦,很棒。我使用data.table几乎完全是为了诚实。如果你不介意,还有一个问题。当我运行data.frame :: duplist时,我得到一个错误[...]不是类型列表。参数不应该是data.table?只是为了澄清,这正是我正在寻找的功能。一旦我对你的问题发表评论,我会接受这个答案。谢谢 - Nikos
尼科斯, uniqlist/duplist 是一个功能 data.table 包。因为它没有导出,你将不得不使用 data.table::: (在哪里 data.table 这里指的是包)运算符来访问该函数。它基本上可以在data.frames / data.tables上运行(因为它需要列表输入)。希望这可以解决问题吗? - Arun
当然。它基本上为您提供每个独特组合的索引。更像 rle,但使用列表,但返回索引而不是值。 - Arun
我才意识到你是一个 data.table 开发者 - 难怪! 提交的问题。 - Heisenberg


完全不可读,但是:

c(1,which(rowSums(sapply(x[,grep('val',names(x))],diff))!=0)+1)
# [1] 1 4 5

基本上,跑 diff 在每一行,找到所有的变化。如果发生变化 任何 列,然后行中发生了更改。

而且,没有 sapply

c(1,which(rowSums(diff(as.matrix(x[,grep('val',names(x))])))!=0)+1)

3
2018-01-21 18:22



+1,注意OP你需要用上面的表达式对data.frame进行子集化(可能很明显,但以防万一......)。 - BrodieG
nograpes,谢谢。完美的工作。虽然在2M线上运行时有点慢。我担心我会依靠Arun的回答(出于多种原因)。感谢您的时间。 - Nikos