我遇到了一个潜在的问题,我希望你能帮助我:)
例如,我有以下数据表显示多个商店,每次访问者进入商店时,都会记录时间和日期。这意味着每行/每行都是1个访问其中一个商店的访客。
data <- structure(list(store.ID = c("1", "1", "1", "1", "1",
"2", "2", "2", "2", "2", "3", "3", "3",
"3", "3", "4", "4", "4", "4", "4"), Time = structure(c(6L,
7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L,
16L, 17L, 18L, 19L, 20L), .Label = c(" 12:09:19", " 12:09:25",
" 13:09:30", " 13:09:35", " 14:09:40", " 12:00:03", " 12:00:09",
" 12:00:14", " 14:00:25", " 16:00:32", " 12:27:19", " 13:27:25",
" 14:27:41", " 14:27:46", " 17:27:59", " 12:46:10", " 12:46:19", " 13:46:29",
" 14:46:39", " 15:46:50"), class = "factor"), Date = structure(c(1351728000,
1351728000, 1351728000, 1351728000, 1351728000, 1351814400, 1351814400,
1351814400, 1351814400, 1351814400, 1351814400, 1351814400, 1351814400,
1351814400, 1351814400, 1351814400, 1351814400, 1351814400, 1351814400,
1351814400), class = c("POSIXct", "POSIXt"), tzone = "UTC")), .Names = c("storeID", "Time", "Date"), class = "data.frame", row.names = c(NA,
-20L))
[编辑] 商店全天候开放。现在我希望有一个解决方案/方式将每个访问/行分配给一天中的24小时时段之一(即,09.00-10.00为1,10.00-11.00为2,等等)。那么我想连续两天每小时的访客人数。我希望能够将某些固定因素分开,例如storeID和City(本例中未显示)。 此外,如果没有访问者进入商店,我希望数据文件显示在此时间间隔内没有访问者,在这种情况下应返回0)。 的 [编辑]
请注意,我的数据文件很大,行数超过700k。
我希望我明白我的问题。
MvZB
答案 0 :(得分:2)
First method:
使用zoo
包as illustrated here very nicely by Dirk。我已经解释了内联代码。这样的事情应该这样做:
df <- data # I just prefer `df` to `data`
df$storeID <- as.numeric(as.character(df$storeID)) # make sure its numeric
# instantiate the zoo object by providing values corresponding to time
require(zoo)
z <- zoo(as.numeric(as.character(df$storeID)),
as.POSIXct(paste(df$Date, df$Time)))
# create output data.frame with all possible timings
open_time <- paste(9:18, "00", "00", sep=":")
open_date <- as.character(unique(df$Date))
out.df <- data.frame(Date = rep(open_date, each=length(open_time)-1),
Start = rep(head(open_time, -1), length(open_date)),
End = rep(tail(open_time, -1), length(open_date)))
# Pointer for matching later
out.df$Pointer <- as.POSIXct(paste(out.df$Date, out.df$Start))
# initialise count to 0
out.df$count <- 0
# aggregate using zoo's magic function!
# the first part contains the storeID and is aggregated by
# the second column which creates hourly interval from the times in z (your data)
# and the third column sums up all values that fall in each hourly interval
agg.out <- aggregate(z, time(z) - as.numeric(time(z)) %% 3600, length)
# once that is done, just match the corresponding times and place them rightly
m.idx <- match( out.df$Pointer, index(agg.out))
out.df$count[!is.na(m.idx)] <- agg.out[m.idx[!is.na(m.idx)]]
out.df <- subset(out.df, select=-c(Pointer))
# and you're done
> out.df
# Date Start End count
# 1 2012-11-01 9:00:00 10:00:00 0
# 2 2012-11-01 10:00:00 11:00:00 0
# 3 2012-11-01 11:00:00 12:00:00 0
# 4 2012-11-01 12:00:00 13:00:00 3
# 5 2012-11-01 13:00:00 14:00:00 0
# 6 2012-11-01 14:00:00 15:00:00 1
# 7 2012-11-01 15:00:00 16:00:00 0
# 8 2012-11-01 16:00:00 17:00:00 1
# 9 2012-11-01 17:00:00 18:00:00 0
# 10 2012-11-02 9:00:00 10:00:00 0
# 11 2012-11-02 10:00:00 11:00:00 0
# 12 2012-11-02 11:00:00 12:00:00 0
# 13 2012-11-02 12:00:00 13:00:00 5
# 14 2012-11-02 13:00:00 14:00:00 4
# 15 2012-11-02 14:00:00 15:00:00 4
# 16 2012-11-02 15:00:00 16:00:00 1
# 17 2012-11-02 16:00:00 17:00:00 0
# 18 2012-11-02 17:00:00 18:00:00 1
Second Method:
不使用zoo
包drawing idea from Dirk
again here。但我使用data.table
进行快速访问。再次查看内联注释以获得解释。
require(data.table)
df <- data # I prefer df than data
# create an id column containing only the hours
df$id <- as.numeric(as.POSIXlt(paste(df$Date, df$Time))$hour)
# convert Date to character
df$Date <- as.character(df$Date)
# load package, create input data.table with Date and id as keys
require(data.table)
dt.in <- data.table(df)
setkey(dt.in, "Date", "id")
# get the count of customers / hour / date
dt.tmp <- dt.in[, .N, by=c("Date", "id")]
# create the output template data.table with Date, Start and End
open_time <- paste(9:18, "00", "00", sep=":")
open_date <- as.character(unique(df$Date))
dt.out <- data.table(Date = rep(open_date, each=length(open_time)-1),
Start = rep(head(open_time, -1), length(open_date)),
End = rep(tail(open_time, -1), length(open_date)))
# create the id again by extracting hour
dt.out[, id := as.numeric(as.POSIXlt(paste(Date, Start))$hour)]
setkey(dt.out, "Date", "id")
# merge the two data.tables to get your output
dt.out <- dt.tmp[dt.out, list(Start, End, N)]
dt.out[, id := NULL]
> dt.out
# Date Start End N
# 1: 2012-11-01 9:00:00 10:00:00 NA
# 2: 2012-11-01 10:00:00 11:00:00 NA
# 3: 2012-11-01 11:00:00 12:00:00 NA
# 4: 2012-11-01 12:00:00 13:00:00 3
# 5: 2012-11-01 13:00:00 14:00:00 NA
# 6: 2012-11-01 14:00:00 15:00:00 1
# 7: 2012-11-01 15:00:00 16:00:00 NA
# 8: 2012-11-01 16:00:00 17:00:00 1
# 9: 2012-11-01 17:00:00 18:00:00 NA
# 10: 2012-11-02 9:00:00 10:00:00 NA
# 11: 2012-11-02 10:00:00 11:00:00 NA
# 12: 2012-11-02 11:00:00 12:00:00 NA
# 13: 2012-11-02 12:00:00 13:00:00 5
# 14: 2012-11-02 13:00:00 14:00:00 4
# 15: 2012-11-02 14:00:00 15:00:00 4
# 16: 2012-11-02 15:00:00 16:00:00 1
# 17: 2012-11-02 16:00:00 17:00:00 NA
# 18: 2012-11-02 17:00:00 18:00:00 1
答案 1 :(得分:2)
这是一个使用lubridate和因子的简单解决方案:
library(lubridate)
# Create a single date time variable
dt <- ymd_hms(paste(data$Date, data$Time))
# Extract the day
data$day <- floor_date(dt, "day")
# Extract the hour, converting it into a factor, so we
# get all hours shown
data$hour <- factor(hour(dt), 9:18)
# Count up with table
as.data.frame(table(data[c("day", "hour")]))