19

私のデータセットの単純化されたバージョンは次のようになります。

depth value
   1     a
   1     b
   2     a
   2     b
   2     b
   3     c

「深さ」の値ごとに、上から順に一意の値の累積数を持つ新しいデータセットを作成したいと思います。例えば

depth cumsum
 1      2
 2      2
 3      3

これを行う方法についてのアイデアはありますか?私はRに比較的慣れていません。

4

6 に答える 6

14

これは、慎重に使用factorおよび設定するのに最適なケースだと思います。この考え方でこちらをlevels使用します。列が(絶対要件ではありません) であるdata.tableことを確認してください。valuecharacter

  • ステップ 1:行だけを取得してdata.frame変換します。data.tableunique

    require(data.table)
    dt <- as.data.table(unique(df))
    setkey(dt, "depth") # just to be sure before factoring "value"
    
  • ステップ 2: a に変換valueし、factorに強制しnumericます。必ず自分でレベルを設定してください(重要です)。

    dt[, id := as.numeric(factor(value, levels = unique(value)))]
    
  • depthステップ3:サブセット化のためにキー列を設定し、最後の値を選択するだけです

     setkey(dt, "depth", "id")
     dt.out <- dt[J(unique(depth)), mult="last"][, value := NULL]
    
    #    depth id
    # 1:     1  2
    # 2:     2  2
    # 3:     3  3
    
  • ステップ 4: 深さが増加する行のすべての値は、少なくとも前の行の値を持つ必要がcummaxあるため、最終的な出力を取得するために使用する必要があります。

    dt.out[, id := cummax(id)]
    

編集:上記のコードは、説明を目的としたものです。実際には、3 列目はまったく必要ありません。これが最終的なコードの書き方です。

require(data.table)
dt <- as.data.table(unique(df))
setkey(dt, "depth")
dt[, value := as.numeric(factor(value, levels = unique(value)))]
setkey(dt, "depth", "value")
dt.out <- dt[J(unique(depth)), mult="last"]
dt.out[, value := cummax(value)]

よりトリッキーな例とコードからの出力を次に示します。

df <- structure(list(depth = c(1, 1, 2, 2, 3, 3, 3, 4, 5, 5, 6), 
                value = structure(c(1L, 2L, 3L, 4L, 1L, 3L, 4L, 5L, 6L, 1L, 1L), 
                .Label = c("a", "b", "c", "d", "f", "g"), class = "factor")), 
                .Names = c("depth", "value"), row.names = c(NA, -11L), 
                class = "data.frame")
#    depth value
# 1:     1     2
# 2:     2     4
# 3:     3     4
# 4:     4     5
# 5:     5     6
# 6:     6     6
于 2013-03-29T09:43:27.083 に答える
8

別の試みを次に示します。

numvals <- cummax(as.numeric(factor(mydf$value)))
aggregate(numvals, list(depth=mydf$depth), max)

これにより、次のことが得られます。

  depth x
1     1 2
2     2 2
3     3 3

@Arunの例でもうまくいくようです:

  depth x
1     1 2
2     2 4
3     3 4
4     4 5
5     5 6
6     6 6
于 2013-03-29T10:19:54.313 に答える
5

TRUE最初のステップとして、 orの列を作成することをお勧めしますFALSE。これはTRUE、各値の最初と、その値FALSEが後で出現するためのものです。これは、次を使用して簡単に実行できますduplicated

mydata$first.appearance = !duplicated(mydata$value)

データの再形成は、 を使用して行うのが最適aggregateです。この場合、 のfirst.appearance各サブセット内の列を合計するように指示されdepthます。

newdata = aggregate(first.appearance ~ depth, data=mydata, FUN=sum)

結果は次のようになります。

  depth first.appearance
1     1  2
2     2  0
3     3  1

ただし、これはまだ累計ではありません。そのために、cumsum関数を使用できます(そして、古い列を取り除きます):

newdata$cumsum = cumsum(newdata$first.appearance)
newdata$first.appearance = NULL

要約すると:

mydata$first.appearance = !duplicated(mydata$value)
newdata = aggregate(first.appearance ~ depth, data=mydata, FUN=sum)
newdata$cumsum = cumsum(newdata$first.appearance)
newdata$first.appearance = NULL

出力:

  depth cumsum
1     1      2
2     2      2
3     3      3
于 2013-03-29T06:37:44.953 に答える
5

これは、 sqldfパッケージを使用して単一の SQL ステートメントで比較的きれいな方法で記述できます。DFが元のデータ フレームであると仮定します。

library(sqldf)

sqldf("select b.depth, count(distinct a.value) as cumsum
    from DF a join DF b 
    on a.depth <= b.depth
    group by b.depth"
)
于 2013-03-29T15:03:14.790 に答える
1

を使用した別のソリューションを次に示しlapply()ます。unique(df$depth)一意の値のベクトルを作成しdepth、そのような値サブセットごとに、特定の値以下のvalue値のみを作成します。次に、一意の値の長さを計算します。この長さの値は に格納され、特定の深度レベルの値が得られます。1つのデータフレームとして作成します。depthdepthvaluecumsumdepth=xdo.call(rbind,...)

do.call(rbind,lapply(unique(df$depth), 
               function(x)
             data.frame(depth=x,cumsum=length(unique(df$value[df$depth<=x])))))
  depth cumsum
1     1      2
2     2      2
3     3      3
于 2013-03-29T06:45:31.463 に答える