R: Заполнение списка из цикла for
Я постепенно изучаю, как работать с заявками и с какими утверждениями в r, но все еще в некотором роде провал в жизни.
У меня есть фрейм данных, df, с 4 столбцами (на самом деле мой набор данных состоит из множества дат за несколько лет с несколькими тысячами user_ids):
>df
id timestamp user_id app_version
1 96 2013-03-05 12 1.05
2 99 2013-03-05 32 1.0.5
3 02 2013-03-05 21 1.05
4 14 2013-03-05 21 1.0.5
5 16 2013-03-05 12 1.0.5
6 32 2013-03-06 32 1.0.3
7 33 2013-03-06 33 1.0.3
8 37 2013-03-06 12 1.0.3
9 39 2013-03-06 21 1.0.3
10 40 2013-03-06 12 1.0.5
И вектор, приложение:
приложение<-c ("1.0.3", "1.0.5", "2,05")
Моя конечная цель - рассчитать среднее число раз, когда пользователь входит в систему в день (т. Е. Среднее количество записей, которые пользователь имеет с одной и той же отметкой времени), разделенное на номер версии (например, для версии приложения 1,05 пользователи имеют среднее значение из 3 входов в день в 2013-03-05). Я могу сделать это вручную через df[which(df$app_version="1.05"),]
, Но я хотел бы пройтись по вектору своего приложения и в конце иметь список фреймов данных, по одному фрейму данных для каждой версии приложения, где каждый фрейм данных содержит даты в виде строк и avg. количество логинов как столбцов). Код ниже - мой подход, но мой окончательный список неверен, так как это список из двух чисел, а не двух фреймов данных. Любая и вся помощь будет находкой. Спасибо!
require(reshape2)
require(dplyr)
require(lubridate)
df$timestamp <- as.Date(df$timestamp) # Converting to date
# Step 1 ------------------------------------------------------------------
# Parsing data into different dataframes for each app version
flist<-vector(mode="list",length=length(app))
fdts<-vector(mode="list",length=length(app))
for (i in 1:length(app)){
appdat<-df[which(df$app_version==app[i]),]
# Step 2 ------------------------------------------------------------------
# Creating table of timestamps as columns, with user_ids making up row
tmp.ndat<-dcast(appdat,id~timestamp,value.var="user_id",drop=TRUE)
# Step 3 ------------------------------------------------------------------
# Createing contingency tables of each day
ctable.day<-apply(tmp.ndat[,-1],2,table)
# Step 4 ------------------------------------------------------------------
# Calculating the avg and stdev for each user for each day
dts<-as.Date(names(ctable.day))
avg.day<-lapply(ctable.day,mean)
sd.day<-lapply(ctable.day,sd)
# Step 5 ------------------------------------------------------------------
# Combine all averages and stdevs, with timestamp as rows and app version as columns
tmp<-cbind(avg.day,sd.day)
tmp.dts<-as.Date(names(ctable.day))
flist[i]<-tmp
fdts[i]<-tmp.dts
}
return(flist)
2 ответа
Глядя на ваш код, кажется, что вы хотите получить среднее число входов в систему по каждому пользователю за каждый день, с каждой версией app_version в отдельном фрейме данных. Таким образом, если в определенный день в приложение заходило 3 пользователя, и они входили в 1,5 и 8 раз соответственно, то среднее значение будет равно (1+5+8)/3. Если это неправильно, дайте мне знать, и я удалю ответ.
Вот один из способов сделать это:
df$counts <- 1
# tmp$count contains number of logins by each user for each app for each day
tmp <- aggregate(counts~user_id+timestamp+app_version,df,sum)
get.stats <- function(x) c(mean=mean(x), sd=sd(x))
result <- lapply(split(tmp,tmp$app_version),
function(dat)aggregate(counts~timestamp+app_version,dat,get.stats))
result <- lapply(result,function(r)with(r,data.frame(timestamp,app_version,counts)))
result
# $`1.0.3`
# timestamp app_version mean sd
# 1 2013-03-06 1.0.3 1 0
#
# $`1.0.5`
# timestamp app_version mean sd
# 1 2013-03-05 1.0.5 1 0
# 2 2013-03-06 1.0.5 1 NA
#
# $`1.05`
# timestamp app_version mean sd
# 1 2013-03-05 1.05 1 0
Этот код создает фиктивный столбец, df$counts
что необходимо для следующего шага. Затем мы агрегируем user_id
, timestamp
, а также app_version
рассчитать количество входов в систему каждого пользователя для каждого приложения в каждый день. Тогда мы используем lapply(split(df,df$app_version), FUN)
разделять df
от app_version
и применить функцию к каждому подмножеству. Функция агрегатов counts
по метке времени (и app_version
, но есть только один в данном подмножестве), чтобы вычислить среднее и сд.
Результаты с вашими примерами данных довольно неинтересны, потому что ни один пользователь не регистрируется более одного раза для данного приложения в определенный день, поэтому все средства равны = 1.
Ваше описание того, что вы пытаетесь сделать, довольно расплывчато. Например, вы упомянули, что хотите получить среднее значение для каждой даты, но среднее значение чего? Вы имеете в виду количество в отличие от среднего? Из того, что я понял, это выглядит как идеальный вариант использования метода split-apply-Объединить, используя функцию из apply
семьи. В частности, tapply
, Вам нужно бежать tapply
и пусть она применяет функцию к фреймам данных, которые подмножествены согласно вашему столбцу версии И вашему столбцу даты. То, что я сделал бы, это сначала разделить все по версии, получив список фреймов данных обратно. Затем пройдите и сделайте tapply
к каждой записи в этом списке.