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 к каждой записи в этом списке.

Другие вопросы по тегам