基于条件的累积总和,但在条件结束后重置

时间:2019-09-26 03:17:13

标签: r grouping cumulative-sum

如何在条件允许的情况下提高累计和重置的性能?

我有一个public void uploadNotesToSTORAGE(final ArrayList<NoteItem> nItems, final Activity activity) { final ProgressDialog dialog = new ProgressDialog(activity); dialog.setMessage("Uploading picture..."); dialog.show(); for (int i = 0; i < nItems.size(); i++) { final String id = Calendar.getInstance().getTimeInMillis() + ""; StorageReference reference = mStorageRef.child("notes/" + id); String filePath = nItems.get(i).getFilePath(); final int finalI = i; final int finalI1 = i; reference.putFile(Uri.fromFile(new File(filePath))).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { StorageReference reference = mStorageRef.child("notes/" + id); reference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() { @Override public void onSuccess(Uri dUri) { nItems.get(finalI).setId(id); nItems.get(finalI).setDownloadLink(dUri + ""); db.collection("notes").document().set(nItems.get(finalI)) .addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { Toast.makeText(activity, "Successfully uploaded : " + nItems.get(finalI1).getFileName(), Toast.LENGTH_SHORT).show(); } }); } }); } }).addOnFailureListener(onFailureListener); dialog.dismiss(); activity.finish(); activity.startActivity(new Intent(activity, MainActivity.class)); } } ,并在变量名data.frame下附加了一个演示数据集。我有一列带有demo的列,该列指出系统发生故障,然后列flag计数该故障连续发生了多少次,并在故障恢复后重置。我正在使用tidyverse软件包,也使用了R。

我一直在阅读有关此问题的一些StackOverflow帖子,但是我似乎无法将思路用tidyverse和/或base R更快地解决。我已经使用for实现了该版本循环,但是对于较大的数据集,计算时间花费的时间过长(对于107388行数据帧,则为9分钟)。有没有更有效的解决方案来解决这个问题?

测试数据集:

continuousfailure

我当前使用的代码是:

demo <- data.frame(data = rnorm(100, mean = 0, sd = 2000), flag = c(rep(FALSE, 5), rep(TRUE, 10), rep(FALSE, 25), rep(TRUE, 23), rep(FALSE, 13), rep(TRUE, 5), rep(FALSE, 19)),
continuousfailure = c(rep(0, 5), 1:10, rep(0, 25), 1:23, rep(0, 13), 1:5, rep(0, 19)),magnitude = NA)

期望的输出预期是相同的,但是使用tidyverse或基数R可以提高函数的速度,通过对逻辑的构造方式的一些解释,也将不胜感激。

谢谢!

2 个答案:

答案 0 :(得分:2)

我们可以使用data.table rleid创建组并根据cumsum返回NAflag

library(dplyr)

demo %>%
  group_by(group = data.table::rleid(flag)) %>%
  mutate(new_mag = if(first(flag)) cumsum(data) else NA) %>%
  ungroup %>%
  select(-group)

#     data flag  continuousfailure magnitude new_mag
#    <dbl> <lgl>             <dbl>     <dbl>   <dbl>
# 1 -1121. FALSE                 0       NA      NA 
# 2  -460. FALSE                 0       NA      NA 
# 3  3117. FALSE                 0       NA      NA 
# 4   141. FALSE                 0       NA      NA 
# 5   259. FALSE                 0       NA      NA 
# 6  3430. TRUE                  1     3430.   3430.
# 7   922. TRUE                  2     4352.   4352.
# 8 -2530. TRUE                  3     1822.   1822.
# 9 -1374. TRUE                  4      448.    448.
#10  -891. TRUE                  5     -443.   -443.
# … with 90 more rows

其中magnitude是具有for循环中的值的列,而new_mag是上面代码的输出。


有多种创建组的方法。如上所示,一个使用rleid,另一个使用lagdplyr

中的cumsum
group_by(group = cumsum(flag != lag(flag, default = first(flag)))) %>%

和另一个base rle

group_by(group = with(rle(flag), rep(seq_along(lengths), lengths)))

您可以用以上任何一项替换group_by行。

数据

set.seed(123)
demo <- data.frame(data = rnorm(100, mean = 0, sd = 2000), 
flag = c(rep(FALSE, 5), rep(TRUE, 10), rep(FALSE, 25), rep(TRUE, 23),rep(FALSE, 13),
rep(TRUE, 5), rep(FALSE, 19)),continuousfailure = c(rep(0, 5), 1:10, rep(0, 25), 
1:23, rep(0, 13), 1:5, rep(0, 19)),magnitude = NA)

答案 1 :(得分:0)

我们可以使用data.table方法

library(data.table)
setDT(demo)[,   new := if(first(flag)) cumsum(data) else NA_real_, rleid(flag)]

数据

set.seed(123)
demo <- data.frame(data = rnorm(100, mean = 0, sd = 2000), 
flag = c(rep(FALSE, 5), rep(TRUE, 10), rep(FALSE, 25), rep(TRUE, 23),rep(FALSE, 13),
rep(TRUE, 5), rep(FALSE, 19)),continuousfailure = c(rep(0, 5), 1:10, rep(0, 25), 
1:23, rep(0, 13), 1:5, rep(0, 19)),magnitude = NA)