16

サンプルデータ:

set.seed(1)
df <- data.frame(years=sort(rep(2005:2010, 12)), 
                 months=1:12, 
                 value=c(rnorm(60),NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA))

head(df)
  years months      value
1  2005      1 -0.6264538
2  2005      2  0.1836433
3  2005      3 -0.8356286
4  2005      4  1.5952808
5  2005      5  0.3295078
6  2005      6 -0.8204684

教えてください、どうすれば df$value の NA を他の月の中央値に置き換えることができますか? 「値」には、同じ月の以前のすべての値の中央値が含まれている必要があります。つまり、現在の月が 5 月の場合、「値」には 5 月の以前のすべての値の中央値が含まれている必要があります。

4

6 に答える 6

15

is.naテスト機能を使用したい:

df$value[is.na(df$value)] <- median(df$value, na.rm=TRUE)

df$valueこれは、であるすべての値についてNA、右側に置き換えます。na.rm=TRUEピースが必要です。そうでない場合、median関数は戻りますNA

今月ごとに行うには、多くの選択肢がありますplyrが、構文は最も単純だと思います。

library(plyr)
ddply(df, 
      .(months), 
      transform, 
      value=ifelse(is.na(value), median(value, na.rm=TRUE), value))

を使用することもできますdata.table。これは、データが大きい場合に特に適しています。

library(data.table)
DT <- data.table(df)
setkey(DT, months)

DT[,value := ifelse(is.na(value), median(value, na.rm=TRUE), value), by=months]

他にもたくさんの方法がありますが、2つあります!

于 2012-08-15T15:14:23.367 に答える
10

または ave で

df <- data.frame(years=sort(rep(2005:2010, 12)),
months=1:12,
value=c(rnorm(60),NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA))
df$value[is.na(df$value)] <- with(df, ave(value, months, 
   FUN = function(x) median(x, na.rm = TRUE)))[is.na(df$value)]

非常に多くの答えがあるので、どれが最も速いか見てみましょう。

plyr2 <- function(df){
  medDF <- ddply(df,.(months),summarize,median=median(value,na.rm=TRUE))
df$value[is.na(df$value)] <- medDF$median[match(df$months,medDF$months)][is.na(df$value)]
  df
}
library(plyr)
library(data.table)
DT <- data.table(df)
setkey(DT, months)


benchmark(ave = df$value[is.na(df$value)] <- 
  with(df, ave(value, months, 
               FUN = function(x) median(x, na.rm = TRUE)))[is.na(df$value)],
          tapply = df$value[61:72] <- 
            with(df, tapply(value, months, median, na.rm=TRUE)),
          sapply = df[61:72, 3] <- sapply(split(df[1:60, 3], df[1:60, 2]), median),
          plyr = ddply(df, .(months), transform, 
                       value=ifelse(is.na(value), median(value, na.rm=TRUE), value)),
          plyr2 = plyr2(df),
          data.table = DT[,value := ifelse(is.na(value), median(value, na.rm=TRUE), value), by=months],
          order = "elapsed")
        test replications elapsed relative user.self sys.self user.child sys.child
3     sapply          100   0.209 1.000000     0.196    0.000          0         0
1        ave          100   0.260 1.244019     0.244    0.000          0         0
6 data.table          100   0.271 1.296651     0.264    0.000          0         0
2     tapply          100   0.271 1.296651     0.256    0.000          0         0
5      plyr2          100   1.675 8.014354     1.612    0.004          0         0
4       plyr          100   2.075 9.928230     2.004    0.000          0         0

data.table が最速だったに違いありません。

[ Matthew Dowle ] ここで計測されているタスクは、せいぜい 0.02 秒 (2.075/100) しかかかりません。data.tableそれは重要ではないと考えます。代わりに、データ サイズを に設定replications1て増やしてみてください。または、3回のうち最速のタイミングを計ることも、一般的な経験則です。これらのリンクでのより詳細な議論:

于 2012-08-15T15:21:52.227 に答える
9

でこれを行う別の方法がありますdplyr

すべての列を中央値に置き換えたい場合は、次のようにします。

library(dplyr)
df %>% 
   mutate_all(~ifelse(is.na(.), median(., na.rm = TRUE), .))

列のサブセット (OP の例の「値」など) を置き換えたい場合は、次のようにします。

df %>% 
  mutate_at(vars(value), ~ifelse(is.na(.), median(., na.rm = TRUE), .))
于 2017-08-13T00:07:58.777 に答える
4

これが私が考えることができる最も堅牢なソリューションです。年が正しく順序付けられていることを確認し、値が欠落している年が複数ある場合に、前のすべての月の中央値を正しく計算します。

# first, reshape your data so it is years by months:
library(reshape2)
tmp <- dcast(years ~ months, data=df)  # convert data to years x months
tmp <- tmp[order(tmp$years),]          # order years
# now calculate the running median on each month
library(caTools)
# function to replace NA with rolling median
tmpfun <- function(x) {
  ifelse(is.na(x), runquantile(x, k=length(x), probs=0.5, align="right"), x)
}
# apply tmpfun to each column and convert back to data.frame
tmpmed <- as.data.frame(lapply(tmp, tmpfun))
# reshape back to long and convert 'months' back to integer
res <- melt(tmpmed, "years", variable.name="months")
res$months <- as.integer(gsub("^X","",res$months))
于 2012-08-15T15:38:18.947 に答える
3

ベースRに固執して、次のことも試すことができます。

medians = sapply(split(df[1:60, 3], df[1:60, 2]), median)
df[61:72, 3] = medians
于 2012-08-15T15:15:11.010 に答える
1

これは を使用する方法plyrです。あまりきれいではありませんが、あなたが望むことはできると思います:

library("plyr")

# Make a separate dataframe with month as first column and median as second:
medDF <- ddply(df,.(months),summarize,median=median(value,na.rm=TRUE))

# Replace `NA` values in `df$value` with medians from the second data frame
# match() here ensures that the medians are entered in the correct elements.
df$value[is.na(df$value)] <- medDF$median[match(df$months,medDF$months)][is.na(df$value)]
于 2012-08-15T15:11:22.817 に答える