如果数据帧中为零,则为条件平均值或替换值

问题描述 投票:0回答:3

我在为以下问题找到正确的代码时遇到问题。

这是我的数据框df的简化和简短版本:

Line  Id   Amount
1      1    10
2      2    12
3      2    13
4      2    0
5      3    11
6      4    12
7      4    14
8      5    0
9      6    11
10     6    0

我想根据以下条件创建另一个列Amount_Avrg:

-如果几行具有相同的ID,且金额不为零,则对于第2行和第3行以及对于第6行和第7行,计算不同金额的平均值

-如果一行的金额等于0,则:

如果单独使用,则将其擦除(如果没有其他行具有相同的ID并且其值不同于0)(第8行的情况)

B /如果有一行具有相同的ID,且其值不同于0(第9和10行的情况,则将0替换为另一行的值

C /如果有两行或更多行的值不为零(第2行和第3行的情况,则用其他金额的平均值替换0]

我期望的最终数据帧看起来像这样:

Line  Id   Amount  Amount_Avrg
1      1    10     10
2      2    12     12.5
3      2    13     12.5 
4      2    0      12.5
5      3    11     11
6      4    12     13
7      4    14     13
9      6    11     11
10     6    0      11

我读过很多答案,如果循环在R上效率不高,那么如果您可以帮助我提供另一种解决方案,那就太好了:-)

r dataframe
3个回答
2
投票

使用dplyr,我们可以group_by ID并取非零meanAmount并删除其中包含NA的行。

library(dplyr)

df %>%
  group_by(Id) %>%
  mutate(mn = mean(Amount[Amount > 0])) %>%
  filter(!is.na(mn))

#   Line    Id Amount  mn
#  <int> <int>  <int> <dbl>
#1     1     1     10  10  
#2     2     2     12  12.5
#3     3     2     13  12.5
#4     4     2      0  12.5
#5     5     3     11  11  
#6     6     4     12  13  
#7     7     4     14  13  
#8     9     6     11  11  
#9    10     6      0  11  

或带有data.table

library(data.table)
setDT(df)[, mn := mean(Amount[Amount > 0]), by = Id][!is.na(mn)]

数据

df <- structure(list(Line = 1:10, Id = c(1L, 2L, 2L, 2L, 3L, 4L, 4L, 
5L, 6L, 6L), Amount = c(10L, 12L, 13L, 0L, 11L, 12L, 14L, 0L, 
11L, 0L)), class = "data.frame", row.names = c(NA, -10L))

1
投票

如果创建所有非零均值的汇总表,则可以将其右连接到原始表,以在问题中显示结果。

library(data.table)
setDT(df)

nonzero_means <- df[Amount > 0, .(Amount_Avg = mean(Amount)), Id]

df[nonzero_means, on = .(Id)]
#    Line Id Amount Amount_Avg
# 1:    1  1     10       10.0
# 2:    2  2     12       12.5
# 3:    3  2     13       12.5
# 4:    4  2      0       12.5
# 5:    5  3     11       11.0
# 6:    6  4     12       13.0
# 7:    7  4     14       13.0
# 8:    9  6     11       11.0
# 9:   10  6      0       11.0

0
投票

您可以使用ave计算每个meanId,然后使用!is.na子集删除每个0仅具有Id的行。

x$Amount_Avrg <-  ave(x$Amount, x$Id, FUN=function(x) mean(x[x>0]))
x  <- x[!is.na(x$Amount_Avrg),]
x
#   Line Id Amount Amount_Avrg
#1     1  1     10        10.0
#2     2  2     12        12.5
#3     3  2     13        12.5
#4     4  2      0        12.5
#5     5  3     11        11.0
#6     6  4     12        13.0
#7     7  4     14        13.0
#9     9  6     11        11.0
#10   10  6      0        11.0

或带有withinna.omit

na.omit(within(x, mount_Avrg <- ave(Amount, Id, FUN=function(x) mean(x[x>0]))))

或使用aggregatemerge

merge(x, aggregate(cbind(Amount_Avrg = Amount) ~ Id, data=x[x$Amount>0,], mean))

数据:

x  <- read.table(header=TRUE, text="Line  Id   Amount
1      1    10
2      2    12
3      2    13
4      2    0
5      3    11
6      4    12
7      4    14
8      5    0
9      6    11
10     6    0")
© www.soinside.com 2019 - 2024. All rights reserved.