web-dev-qa-db-ja.com

グループごとの観測/行の数をカウントし、結果をデータフレームに追加します

たとえば、data.frameオブジェクト:

df <- data.frame(name=c('black','black','black','red','red'),
                 type=c('chair','chair','sofa','sofa','plate'),
                 num=c(4,5,12,4,3))

次に、nametypeの各組み合わせの観測数をカウントします。これは次のように実行できます。

table(df[ , c("name","type")])

または場合によってはplyrも使用します(ただし、方法はわかりません)。

ただし、元のデータフレームに結果を組み込むにはどうすればよいですか?結果は次のようになります。

df
#    name  type num count
# 1 black chair   4     2
# 2 black chair   5     2
# 3 black  sofa  12     1
# 4   red  sofa   4     1
# 5   red plate   3     1

ここで、countには、集計の結果が格納されます。

plyrを使用したソリューションも興味深いものになりますが、これがベースRでどのように行われるかを知りたいと思います。

45
Uri Laserson

plyr:を使用

plyr::ddply(df, .(name, type), transform, count = length(num))

data.table:を使用

library(data.table)
dt = data.table(df)
# using setkey or setkeyv to set the key
setkeyv(dt, c('name', 'type'))
# self 
dt[dt[ , count = length(num), 'name, type']]

編集(mnel)

data.tableバージョン1.8.2以降を使用すると、グループごとに:=が使用されます。値.N(バージョン1.6.2を導入)もあります。これはグループ内の行数です)、次のように簡単です。

dt[ , count := .N, by = list(name, type)]

dplyr:を使用

library(dplyr)
df %>%
  group_by(name, type) %>%
  mutate(count = n())

または単に:

add_count(df, name, type)
58
Ramnath

aveを使用できます:

df$count <- ave(df$num, df[,c("name","type")], FUN=length)
26
Joshua Ulrich

あなたはこれを行うことができます:

> ddply(df,.(name,type),transform,count = NROW(piece))
   name  type num count
1 black chair   4     2
2 black chair   5     2
3 black  sofa  12     1
4   red plate   3     1
5   red  sofa   4     1

またはおそらくより直感的に、

> ddply(df,.(name,type),transform,count = length(num))
   name  type num count
1 black chair   4     2
2 black chair   5     2
3 black  sofa  12     1
4   red plate   3     1
5   red  sofa   4     1
7
joran

これはあなたの仕事をするはずです:

df_agg <- aggregate(num~name+type,df,FUN=NROW)
names(df_agg)[3] <- "count"
df <- merge(df,df_agg,by=c('name','type'),all.x=TRUE)
5
Palash Jhamb

ベースR関数aggregateは、1行でカウントを取得しますが、それらのカウントを元のdata.frameは少し処理がかかるようです。

df <- data.frame(name=c('black','black','black','red','red'),
                 type=c('chair','chair','sofa','sofa','plate'),
                 num=c(4,5,12,4,3))
df
#    name  type num
# 1 black chair   4
# 2 black chair   5
# 3 black  sofa  12
# 4   red  sofa   4
# 5   red plate   3

rows.per.group  <- aggregate(rep(1, length(paste0(df$name, df$type))),
                             by=list(df$name, df$type), sum)
rows.per.group
#   Group.1 Group.2 x
# 1   black   chair 2
# 2     red   plate 1
# 3   black    sofa 1
# 4     red    sofa 1

my.summary <- do.call(data.frame, rows.per.group)
colnames(my.summary) <- c(colnames(df)[1:2], 'rows.per.group')
my.data <- merge(df, my.summary, by = c(colnames(df)[1:2]))
my.data
#    name  type num rows.per.group
# 1 black chair   4              2
# 2 black chair   5              2
# 3 black  sofa  12              1
# 4   red plate   3              1
# 5   red  sofa   4              1
3
Mark Miller

sqldfパッケージを使用:

library(sqldf)

sqldf("select a.*, b.cnt
       from df a,
           (select name, type, count(1) as cnt
            from df
            group by name, type) b
      where a.name = b.name and
            a.type = b.type")

#    name  type num cnt
# 1 black chair   4   2
# 2 black chair   5   2
# 3 black  sofa  12   1
# 4   red  sofa   4   1
# 5   red plate   3   1
2
zx8754

行カウントを基本データセットに組み込むには、わずか1ステップでした。

broomパッケージのtidy()関数を使用して、頻度テーブルをデータフレームに変換し、dfとの内部結合を作成します。

df <- data.frame(name=c('black','black','black','red','red'),
                         type=c('chair','chair','sofa','sofa','plate'),
                         num=c(4,5,12,4,3))
library(broom)
df <- merge(df, tidy(table(df[ , c("name","type")])), by=c("name","type"))
df
   name  type num Freq
1 black chair   4    2
2 black chair   5    2
3 black  sofa  12    1
4   red plate   3    1
5   red  sofa   4    1
1
RobertF

2行の代替方法は、0の変数を生成し、次のように_split<-_、split、およびlengthsで埋めることです。

_# generate vector of 0s
df$count <-0L

# fill it in
split(df$count, df[c("name", "type")]) <- lengths(split(df$num, df[c("name", "type")]))
_

これは望ましい結果を返します

_df
   name  type num count
1 black chair   4     2
2 black chair   5     2
3 black  sofa  12     1
4   red  sofa   4     1
5   red plate   3     1
_

基本的に、RHSは各名前とタイプの組み合わせの長さを計算し、「red.chair」と「black.plate」に対して0の長さ6の名前付きベクトルを返します。これは_split <-_でLHSに供給されます。これはベクトルを取得し、指定されたスポットに適切に値を追加します。 aveの2行目から最終行までがわかるように、これは基本的にaveが行うことです。

_split(x, g) <- lapply(split(x, g), FUN)
_

ただし、lengthssapply(list, length)の最適化バージョンです。

1
lmo