2017-05-02 17 views
1

2つの他の列(最大と最小の列)に基づいて選択する必要がある4列の値(V1〜V4列)のデータフレーム(df)があります。私の目標は、行ごとに最大と最小の列で設定された範囲外の値にNAsを割り当て、残りの値の平均を計算することです。R:行範囲に基づいて行の値を選択

V1 V2 V3 V4 max min 
1 3 6 8  7 5 
23 30 5 17 30 16 

予想される出力は次のようになります。

これまで
V1 V2 V3 V4 max min mean 
NA NA 6 NA  7 5  6 
23 30 NA 17 30 16 35 

が、私は唯一のNASに割り当てるには、以下のスクリプトを使用してこれを行うことができます...

df$V1 <- ifelse(df$V1 > df$max | df$V1 < df$min, NA, df$V1)

df$V2 <- ifelse(df$V2 > df$max | df$V2 < df$min, NA, df$V2)

df$V3 <- ifelse(df$V3 > df$max | df$V3 < df$min, NA, df$V3)

df$V4 <- ifelse(df$V4 > df$max | df$V4 < df$min, NA, df$V4)

...そして平均値を計算するには、次

df$mean <- rowMeans(df[, 1:4], na.rm = TRUE)

の問題は、実際のデータの列数4よりもはるかに大きくなり、このメソッドはあまりにも多くの繰り返しを必要とするようです。 Rでこれを行うより良い方法はありますか?私はその後、成功せずapply機能を使用するために有効な値をサブセットするdata.tableを使用してみましたが

df <- df[df[,1:4] <= df$max | df[,1:4] >= df$min, ]

apply(df[,1:4], 1, function(x) mean(x))

ありがとうございました。

+0

ルックを返します。返信いただきありがとうございます。 – coffeinjunky

答えて

1

試行:

df <- read.table(header=TRUE, text="V1 V2 V3 V4 max min 
1 3 6 8  7 5 
23 30 5 17 30 16") 

df.new<-apply(df[,1:4],2,function(x) ifelse(x>df[,5] | x<df[,6],NA,x)) 
df.new<-cbind(df.new,df[,5:6]) 
df.new$mean=rowMeans(df.new[1:4],na.rm=TRUE) 
df.new 
+0

これは私が探していたものです...もちろん、列に「適用する」! – sjbka

2

たとえば、まずデータを溶かして次のことを試すことができます。

# getting your data: 
df <- read.table(text="V1 V2 V3 V4 max min 
         1 3 6 8  7 5 
         23 30 5 17 30 16", header=T) 

# melting the data: 
library(reshape2) 
df2 <- melt(df, id.vars = c("max", "min")) 
df2 
max min variable value 
1 7 5  V1  1 
2 30 16  V1 23 
3 7 5  V2  3 
4 30 16  V2 30 
5 7 5  V3  6 
6 30 16  V3  5 
7 7 5  V4  8 
8 30 16  V4 17 

# I create a new vector with NAs, but you could easily just overwrite the values: 
df2$val <- with(df2, ifelse(value > max | value < min, NA, value)) 

# Cast the data into the old form again. 
df3 <- dcast(df2, max + min ~ variable, value.var = "val") 
# calculate the rowMeans: 
df3$mean <- rowMeans(df3[, 3:6], na.rm = TRUE) 

# Doing some cosmetics here to get the same column ordering. Chose your preferred way or rearranging the columns, if required at all. 
df3 <- df3[, c(paste0("V", 1:4),"max", "min", "mean") ] 
df3 
    V1 V2 V3 V4 max min  mean 
1 NA NA 6 NA 7 5 6.00000 
2 23 30 NA 17 30 16 23.33333 

唯一の違いは、2番目の行の平均が低いことです。私はあなたがそこで35の価値をどのように得ているか分かりません。

+0

'melt'を使うと動作しますが、多数のカラムが問題を引き起こす可能性があると思います。(長いデータ列を作成するとかなり遅くなりました)ありがとう。 – sjbka

1

ここでは、各行の平均値を計算するために、NASとrowMeansに充填するforループを備えたシンプルなソリューションです。

# loop through rows and fill in NA for values outside of min/max 
for(i in 1:nrow(df)) 
    is.na(df[i, 1:4]) <- df[i, 1:4] < df[i, "min"] | df[i, 1:4] > df[i, "max"] 

# calculate mean of each row 
df$mean <- rowMeans(df[, 1:4], na.rm=TRUE) 

これはmelt` `で

df 
    V1 V2 V3 V4 max min  mean 
1 NA NA 6 NA 7 5 6.00000 
2 23 30 NA 17 30 16 23.33333 
+0

ご返信ありがとうございます。はい、しかし、私は可能なときに 'for'ループを避ける方が好きです。 – sjbka

+1

あなたが知っているように、 '* apply'関数はすべて実際にはループです。 'lapply'のループがcで実装されている間、' apply'のループは実際には 'for'ループとして実装されます。 'apply'のコードを読むことでこれを見ることができます。 (タイプはコンソールにかっこなしで入力し、Enterキーを押します)。 – lmo

関連する問題