[英]Efficient dataframe looping in R
我想遍歷以下data.frame並按由X2中的值確定的順序條目進行分組。 因此,在以下data.frame中,我們可以看到四個組:1-3、5-6、9-13和16。我們可以具有組大小和組數的任意組合。
X1 X2 X3 X4
1 1_21/08/2014 22:56CONTENT_ACCESS.preparing 1 21/08/2014 22:56 CONTENT_ACCESS.preparing
2 2_21/08/2014 22:57CONTENT_ACCESS.preparing 2 21/08/2014 22:57 CONTENT_ACCESS.preparing
3 3_21/08/2014 22:58CONTENT_ACCESS.preparing 3 21/08/2014 22:58 CONTENT_ACCESS.preparing
4 5_21/08/2014 23:07CONTENT_ACCESS.preparing 5 21/08/2014 23:07 CONTENT_ACCESS.preparing
5 6_21/08/2014 23:08CONTENT_ACCESS.preparing 6 21/08/2014 23:08 CONTENT_ACCESS.preparing
6 9_21/08/2014 23:29CONTENT_ACCESS.preparing 9 21/08/2014 23:29 CONTENT_ACCESS.preparing
7 10_21/08/2014 23:30CONTENT_ACCESS.preparing 10 21/08/2014 23:30 CONTENT_ACCESS.preparing
8 11_21/08/2014 23:31CONTENT_ACCESS.preparing 11 21/08/2014 23:31 CONTENT_ACCESS.preparing
9 12_21/08/2014 23:33CONTENT_ACCESS.preparing 12 21/08/2014 23:33 CONTENT_ACCESS.preparing
10 13_21/08/2014 23:34CONTENT_ACCESS.preparing 13 21/08/2014 23:34 CONTENT_ACCESS.preparing
11 16_21/08/2014 23:40CONTENT_ACCESS.preparing 16 21/08/2014 23:40 CONTENT_ACCESS.preparing
我想捕獲X3中的時間戳,以便它們可以描述時間范圍(即每個組的第一個和最后一個時間戳)並產生此輸出。 start_ts是每個組中的第一個時間戳記,stop_ts是每個組中的最后一個時間戳記:
student_id session_id start_ts stop_ts week micro_process
1 4 16 21/08/2014 22:56 21/08/2014 22:58 4 TASK
2 4 16 21/08/2014 23:07 21/08/2014 23:08 4 TASK
3 4 16 21/08/2014 23:29 21/08/2014 23:34 4 TASK
3 4 16 21/08/2014 23:40 21/08/2014 23:40 4 TASK
我還沒有嘗試過循環,但是想看看如何在不使用傳統循環的情況下進行循環。 我的代碼當前僅捕獲整個組的范圍:
student_id session_id start_ts stop_ts week micro_process
1 4 16 21/08/2014 22:58 21/08/2014 23:30 4 TASK
在我的示例中,其他變量(學生ID等)已被虛擬化,並沒有嚴格的相關性,但是為了完整起見,我想保留它們。
代碼(可以直接運行):
library(stringr)
options(stringsAsFactors = FALSE)
eventised_session <- data.frame(student_id=integer(),
session_id=integer(),
start_ts=character(),
stop_ts=character(),
week=integer(),
micro_process=character())
string_match.df <- structure(list(X1 = c("1_21/08/2014 22:56CONTENT_ACCESS.preparing",
"2_21/08/2014 22:57CONTENT_ACCESS.preparing", "3_21/08/2014 22:58CONTENT_ACCESS.preparing",
"5_21/08/2014 23:07CONTENT_ACCESS.preparing", "6_21/08/2014 23:08CONTENT_ACCESS.preparing",
"9_21/08/2014 23:29CONTENT_ACCESS.preparing", "10_21/08/2014 23:30CONTENT_ACCESS.preparing",
"11_21/08/2014 23:31CONTENT_ACCESS.preparing", "12_21/08/2014 23:33CONTENT_ACCESS.preparing",
"13_21/08/2014 23:34CONTENT_ACCESS.preparing", "16_21/08/2014 23:40CONTENT_ACCESS.preparing"
), X2 = c("1", "2", "3", "5", "6", "9", "10", "11", "12", "13",
"16"), X3 = c("21/08/2014 22:56", "21/08/2014 22:57", "21/08/2014 22:58",
"21/08/2014 23:07", "21/08/2014 23:08", "21/08/2014 23:29", "21/08/2014 23:30",
"21/08/2014 23:31", "21/08/2014 23:33", "21/08/2014 23:34", "21/08/2014 23:40"
), X4 = c("CONTENT_ACCESS.preparing", "CONTENT_ACCESS.preparing",
"CONTENT_ACCESS.preparing", "CONTENT_ACCESS.preparing", "CONTENT_ACCESS.preparing",
"CONTENT_ACCESS.preparing", "CONTENT_ACCESS.preparing", "CONTENT_ACCESS.preparing",
"CONTENT_ACCESS.preparing", "CONTENT_ACCESS.preparing", "CONTENT_ACCESS.preparing"
)), .Names = c("X1", "X2", "X3", "X4"), row.names = c(NA, -11L
), class = "data.frame")
r_student_id <- 4
r_session_id <- 16
r_week <- 4
r_mic_proc <- "TASK"
string_match.df
#Get the first and last timestamp in matched sequence
r_start_ts <- string_match.df[1, ncol(string_match.df)-1]
r_stop_ts <- string_match.df[nrow(string_match.df), ncol(string_match.df)-1]
eventised_session[nrow(eventised_session)+1,] <- c(r_student_id, r_session_id, r_start_ts, r_stop_ts, r_week, r_mic_proc)
eventised_session
非常感謝您在這方面的專業知識。 我只使用過傳統的循環。
我們轉換為數字,減去一個序列,以便將相鄰數字轉換為相同的數字。 由於您沒有提供與示例數據名稱不同的所需輸出和引用列名稱,因此我猜測最終結果(基於其他答案):
string_match.df$X2 = as.numeric(string_match.df$X2)
string_match.df$grp = string_match.df$X2 - 1:nrow(string_match.df)
string_match.df
library(dplyr)
string_match.df %>%
group_by(grp) %>%
summarize(start = first(X3), stop = last(X3))
# grp start stop
# <dbl> <chr> <chr>
# 1 0 21/08/2014 22:56 21/08/2014 22:58
# 2 1 21/08/2014 23:07 21/08/2014 23:08
# 3 3 21/08/2014 23:29 21/08/2014 23:34
# 4 5 21/08/2014 23:40 21/08/2014 23:40
作為附帶說明,請小心使用“矩陣”一詞。 您在問題中使用了matrix標記並多次使用了單詞matrix
,但是您沒有matrix
,也不應使用它。 您有一個data.frame
。 在matrix
,所有數據必須為同一類型。 在數據框中,列可以具有不同的類型。 在這里,您有一個數字列,兩個字符串列和一個datetime列,因此矩陣是一個不好的選擇。 每個列都可以屬於適當類別的數據框要好得多。
我為數據使用了一個較短的名稱,並將df $ X2轉換為數字:
df <- string_match.df # as defined in OP
df$X2 <- as.numeric(df$X2)
您可以結合使用cumsum
和diff
來拆分數據幀:
cumsum(diff(c(0,as.numdf$X2))>1)
# [1] 0 0 0 1 1 2 2 2 2 2 3
# presumes that df$X2[1] is 1, but you can easily make up a general case:
# cumsum(diff(c(df$X2[1]-1,df$X2))>1)
現在只需使用split
和lapply
:
do.call(rbind,lapply(split(df, cumsum(diff(c(0,df$X2))>1)), function(x) {foo <- x$X3; data.frame(start_ts=foo[1], stop_ts=tail(foo,1))}))
# output:
start_ts stop_ts
0 21/08/2014 22:56 21/08/2014 22:58
1 21/08/2014 23:07 21/08/2014 23:08
2 21/08/2014 23:29 21/08/2014 23:34
3 21/08/2014 23:40 21/08/2014 23:40
剩下的就是根據需要格式化輸出的問題。
您的新問題可以在tidyverse
輕松tidyverse
。 您要做的主要事情是根據timestamp
變量將觀察結果分組。 我假設規則是自上次觀察以來超過2分鍾會開始一個新小組。 您可以根據需要輕松地進行更改。
將觀察結果分組后,您可以簡單地使用summarize
以按組返回計算結果(在這種情況下,第一個和最后一個時間點):
library(dplyr)
library(lubridate)
string_match.df %>%
select('id' = X2, # Select and rename variables
'timestamp' = X3) %>%
mutate(timestamp = dmy_hm(timestamp), # Parse timestamp as date
time_diff = timestamp - lag(timestamp), # Calculate time from last obs
new_obs = time_diff > 2) | # New obs. if >2 min from last one
is.na(time_diff), # or, if it's the 1st obs.
group_id = cumsum(new_obs)) %>% # Count new groups for group ID
group_by(group_id) %>% # Group by 'group_id'
summarize(start_ts = min(timestamp), # Then return the first and last
stop_ts = max(timestamp)) # timestamps for each group
# A tibble: 4 x 3
group_id start_ts stop_ts
<int> <dttm> <dttm>
1 1 2014-08-21 22:56:00 2014-08-21 22:58:00
2 2 2014-08-21 23:07:00 2014-08-21 23:08:00
3 3 2014-08-21 23:29:00 2014-08-21 23:34:00
4 4 2014-08-21 23:40:00 2014-08-21 23:40:00
由於您的問題中沒有討論如何確定student_id
, session_id
, week
和micro_process
,因此我從示例中省略了它們。 之后,您可以輕松地將它們添加到表中,或者如果新規則是通過分析組的數據確定的,則可以將它們添加到summarize
調用中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.