2017-04-14 5 views
2

前の列に一意のエントリを検索しdplyrを使用する方法:私は多かれ少なかれ、以下の構造で、本当に長いデータフレームを持って

 dates unique_ids sum_values 
1 2011-10-01   2   36 
2 2011-10-02   3   38 
3 2011-10-03   4   43 
4 2011-10-04   4   43 
5 2011-10-05   4   53 
6 2011-10-06   5   58 

df <- data.frame(
dates = c("2011-10-01","2011-10-01","2011-10-01","2011-10-02","2011-10-03","2011-10-05","2011-10-06","2011-10-06"), 
ids = c("A","A","B","C","D","A","E","D"), 
values = c(10,1,25,2,5,10,4,1)) 

> df 
     dates ids values 
1 2011-10-01 A  10 
2 2011-10-01 A  1 
3 2011-10-01 B  25 
4 2011-10-02 C  2 
5 2011-10-03 D  5 
6 2011-10-05 A  10 
7 2011-10-06 E  4 
8 2011-10-06 D  1 

私は次の出力を取得したいと思い

つまり、各日付についてunique_idsは、より前の日付に対応するユニークIDの数を示し、sum_valuesは、より早い日付に対応する値の合計を示します。

オリジナルのdfが大きすぎるので、私は間違いなくサイクルを避けたいと思います。だから私はdplyrを使うことを考えていた。

私はunique_ids列を取得する方法がわからないsum_value

df %>% 
group_by(dates) %>% 
summarize(sum_values_daily = sum(values)) %>% 
mutate(sum_values = cumsum(sum_values_daily)) %>% 
select(dates, sum_values) 

を取得する方法を知っています。

+0

'DF%>%GROUP_BY(日付)%>%のsummarize(unique_ids = n_distinct(IDS)、 sum_values =合計(値))' –

+0

こんにちはRonak、何を返します。 私はuniques_idsとして特定の日付に対して、前の日付のすべてのユニークIDの数と前の日付に対応する値の合計を求めます。 – gico

+1

あなたの予想される出力を再確認してください、私はその正しいとは思わない。 – mtoto

答えて

1

あなたがグループ間で明確なidsの数を計算しようとしているので、まず私たちは私たちだけユニーク値を合計することができますブール列を定義する必要があります。

第2に、元のdfの欠落した日付を予想される出力に含めたいので、完全な日付順でright_joinを実行する必要があります。あなたのdates列は既にクラスDateであると仮定します。これにより、NAの値が生成され、replace0となります。

最後に、unique_idssum_valuesの両方についてcumsumを計算します。いくつかの準備を、私たちは毎日の中に固有のIDとの合計値を収集するよりも:

library(dplyr) 

df %>% mutate(unique_ids = !duplicated(ids)) %>% 
     group_by(dates) %>% 
     summarise(unique_ids = sum(unique_ids), 
        sum_values = sum(values)) %>% 
     right_join(data.frame(dates = seq(min(df$date), 
              max(df$dates), 
              by = 1))) %>% 
     mutate_each(funs(replace(., is.na(.), 0)), -dates) %>% 
     mutate_each(funs(cumsum), -dates) 
#  dates unique_ids sum_values 
#  <date>  <dbl>  <dbl> 
#1 2011-10-01   2   36 
#2 2011-10-02   3   38 
#3 2011-10-03   4   43 
#4 2011-10-04   4   43 
#5 2011-10-05   4   53 
#6 2011-10-06   5   58 
0
library(dplyr) 
library(purrr) 
df %>% 
    mutate(dates = as.Date(dates), ids = as.character(ids)) %>% 
    group_by(dates) %>% 
    summarise(ids = list(unique(ids)), values = sum(values)) %>% 
    merge(data.frame(dates = seq.Date(min(.$dates), max(.$dates), "day")), all.y = TRUE) %>% 
    transmute(
     dates, 
     uniqe_ids = map_int(accumulate(ids, ~unique(c(.x, .y))), length), 
     sum_values = accumulate(values, ~sum(.x, .y, na.rm = TRUE)) 
    ) 

最初の部分、mutategroup_by、その後summarise私が推測するには、理解しやすいです。結果は次のとおりです。

# A tibble: 5 × 3 
     dates  ids values 
     <date> <list> <dbl> 
1 2011-10-01 <chr [2]>  36 
2 2011-10-02 <chr [1]>  2 
3 2011-10-03 <chr [1]>  5 
4 2011-10-05 <chr [1]>  10 
5 2011-10-06 <chr [2]>  5 

その後、我々は可能な日付のギャップを埋めるためdata.frame(dates = seq.Date(min(.$dates), max(.$dates), "day"))でこれをマージします。

今度は、idsvaluesという変数で歩行を上から下に累積的にソートする必要があります。 idsについては、まずpurrr::accumulateと​​の機能を使用します。これは、最初のセルがidsで始まり、それを次のセルと段階的に連結することを意味します(c)。だから、我々の場合には、これはと評価されます:

[[1]] 
[1] "A" "B" 

[[2]] 
[1] "A" "B" "C" 

[[3]] 
[1] "A" "B" "C" "D" 

[[4]] 
[1] "A" "B" "C" "D" 

[[5]] 
[1] "A" "B" "C" "D" "E" 

しかし、我々は、我々はpurrr::map_intの助けを借りて、それにlength機能をマッピングするように異なるIDの数だけを知っている必要があります。

sum_valuesの場合は、累積合計を計算します(マージ後にNAsを持つ可能性があるため、cumsumは使用できません)。

2

代わりに、ここにはdata.tableの解決策があります。わかりやすくするために、私は3行バージョンを提示しますが、これらの行は1行に連結できます。

library(data.table) 
# convert to data.table and make dates a Data data type 
setDT(df)[, "dates" := as.Date(dates)] 
# merge on the daily values (missing 10-04 in original data) 
# convert NAs to 0 for missing dates, calculate cumulative sums of unique ID and values 
df <- df[.(seq.Date(min(dates), max(dates), by="day")), on="dates", 
     .(dates, values=cumsum(ifelse(is.na(values), 0, values)), 
      unique_ids=cumsum(!duplicated(ids) & !is.na(ids)))] 
# aggregate by date, saving the max of unique ID and value 
df <- df[, .(unique_ids=max(unique_ids), sum_values=max(values)), by=dates] 

これは

df 
     dates unique_ids sum_values 
1: 2011-10-01   2   36 
2: 2011-10-02   3   38 
3: 2011-10-03   4   43 
4: 2011-10-04   4   43 
5: 2011-10-05   4   53 
6: 2011-10-06   5   58 
+1

@mtoto他のNAをキャッチしてくれてありがとう...あなたの2番目の点では、部分的に正しいです。上記の 'setDT(df)[、" dates =:as.Date(dates)] 'のように':= 'を使用すると、data.tableは参照によって代入します。しかし、他のほとんどの操作では、コピーを作成します(別の例外は 'set'です)。これを見るには、2行目に 'df <--'を入れずに、私のコードの最初の2行を試してみてください。コンソールに 'df'を表示してください。 10-04が不足していることがわかります。 – lmo

関連する問題