Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
13 0 14 0 16 0 22 0 20 0 18 0
30 0 30 0 0 0 0 0 0 0 30 0
0 0 29 33 0 48 0 49 0 50 0 33
0 45 30 0 0 55 0 69 55 0 0 40
0 54 0 45 0 48 0 73 0 46 0 36
16 0 15 0 13 0 16 0 24 0 23 0
0 32 26 0 0 57 0 65 49 0 0 32
6 0 6 0 5 0 7 0 6 0 6 0
0 665 310 271 0 646 0 706 0 585 0 516
0 70 41 0 0 101 0 112 112 0 0 90
我目前有这个稀疏的数据框,我想在其中将所有0替换为右边的值的一半,并将12月的零替换为1月份的一半。
例如,第一行应如下所示:
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
6.5 7 7 8 8 11 11 10 10 9 9 6.5
所以基本上这一年的总数应该保持不变,并且应该在几个月内更均匀地分布。
我试过使用循环但是我的实际数据跨越了多年,数十万行和循环太慢了。我知道apply是要走的路,但无法弄清楚我的函数应该是什么,或者如何将它应用于行和列。
由于
答案 0 :(得分:5)
我让dfout
保持原始df
完好无损。 dfv2
告诉我们应该在dfout
和dfv3
中放置的值有助于找到应该划分哪些列(已被替换的列)。条件df==0
是此解决方案中的关键元素。我希望有人向此发布data.table或dplyr解决方案。
dfout <- df
dfv2 <- data.frame(df[,-1], Jan = df[,1])
dfv3 <- data.frame(Dec = df[,12], df[,-12])
dfout[df==0] <- dfv2[df==0]
dfout[df==0 | dfv3==0] <- dfout[df==0 | dfv3==0] / 2
rowSums(df) - rowSums(dfout)
# [1] 0 0 0 0 0 0 0 0 0 0
dfout
# Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
# 1 6.5 7.0 7.0 8.0 8.0 11.0 11.0 10.0 10.0 9.0 9.0 6.5
# 2 15.0 15.0 15.0 0.0 0.0 0.0 0.0 0.0 0.0 15.0 15.0 15.0
# 3 0.0 14.5 14.5 33.0 24.0 24.0 24.5 24.5 25.0 25.0 16.5 16.5
# 4 22.5 22.5 30.0 0.0 27.5 27.5 34.5 34.5 55.0 0.0 20.0 20.0
# 5 27.0 27.0 22.5 22.5 24.0 24.0 36.5 36.5 23.0 23.0 18.0 18.0
# 6 8.0 7.5 7.5 6.5 6.5 8.0 8.0 12.0 12.0 11.5 11.5 8.0
# 7 16.0 16.0 26.0 0.0 28.5 28.5 32.5 32.5 49.0 0.0 16.0 16.0
# 8 3.0 3.0 3.0 2.5 2.5 3.5 3.5 3.0 3.0 3.0 3.0 3.0
# 9 332.5 332.5 310.0 271.0 323.0 323.0 353.0 353.0 292.5 292.5 258.0 258.0
# 10 35.0 35.0 41.0 0.0 50.5 50.5 56.0 56.0 112.0 0.0 45.0 45.0
<强> 数据:的强>
df <- structure(list(Jan = c(13L, 30L, 0L, 0L, 0L, 16L, 0L, 6L, 0L,
0L), Feb = c(0L, 0L, 0L, 45L, 54L, 0L, 32L, 0L, 665L, 70L), Mar = c(14L,
30L, 29L, 30L, 0L, 15L, 26L, 6L, 310L, 41L), Apr = c(0L, 0L,
33L, 0L, 45L, 0L, 0L, 0L, 271L, 0L), May = c(16L, 0L, 0L, 0L,
0L, 13L, 0L, 5L, 0L, 0L), Jun = c(0L, 0L, 48L, 55L, 48L, 0L,
57L, 0L, 646L, 101L), Jul = c(22L, 0L, 0L, 0L, 0L, 16L, 0L, 7L,
0L, 0L), Aug = c(0L, 0L, 49L, 69L, 73L, 0L, 65L, 0L, 706L, 112L
), Sep = c(20L, 0L, 0L, 55L, 0L, 24L, 49L, 6L, 0L, 112L), Oct = c(0L,
0L, 50L, 0L, 46L, 0L, 0L, 0L, 585L, 0L), Nov = c(18L, 30L, 0L,
0L, 0L, 23L, 0L, 6L, 0L, 0L), Dec = c(0L, 0L, 33L, 40L, 36L,
0L, 32L, 0L, 516L, 90L)), .Names = c("Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"), class =
"data.frame", row.names = c(NA, -10L))
如果您想让所有元素都为非零,您可以使用while
:
original.df <- df
while(any(df==0)) {
dfout <- df
dfv2 <- data.frame(df[,-1], Jan = df[,1])
dfv3 <- data.frame(Dec = df[,12], df[,-12])
dfout[df==0] <- dfv2[df==0]
dfout[df==0 | dfv3==0] <- dfout[df==0 | dfv3==0] / 2
df <- dfout
}
rowSums(original.df) - rowSums(dfout)
# [1] 0 0 0 0 0 0 0 0 0 0
dfout
# Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
# 1 6.5 7.0 7.0 8.00 8.00 11.00 11.00 10.0 10.0 9.0 9 6.5
# 2 15.0 15.0 15.0 0.23 0.23 0.47 0.94 1.9 3.8 7.5 15 15.0
# 3 7.2 7.2 14.5 33.00 24.00 24.00 24.50 24.5 25.0 25.0 16 16.5
# 4 22.5 22.5 30.0 13.75 13.75 27.50 34.50 34.5 55.0 10.0 10 20.0
# 5 27.0 27.0 22.5 22.50 24.00 24.00 36.50 36.5 23.0 23.0 18 18.0
# 6 8.0 7.5 7.5 6.50 6.50 8.00 8.00 12.0 12.0 11.5 12 8.0
# 7 16.0 16.0 26.0 14.25 14.25 28.50 32.50 32.5 49.0 8.0 8 16.0
# 8 3.0 3.0 3.0 2.50 2.50 3.50 3.50 3.0 3.0 3.0 3 3.0
# 9 332.5 332.5 310.0 271.00 323.00 323.00 353.00 353.0 292.5 292.5 258 258.0
# 10 35.0 35.0 41.0 25.25 25.25 50.50 56.00 56.0 112.0 22.5 22 45.0