可以根据现有列

时间:2015-07-28 03:22:54

标签: r dictionary dataframe

我有一个data.frame df,其中列x用整数(1-9)填充。我想根据x的值更新y和z列,如下所示:

if x is 1,2, or 3 | y = 1 ## if x is 1,4, or 7 | z = 1 
if x is 4,5, or 6 | y = 2 ## if x is 2,5, or 8 | z = 2 
if x is 7,8, or 9 | y = 3 ## if x is 3,6, or 9 | z = 3

以下是包含yz

所需输出的data.frame
df <- structure(list(x = c(1L, 2L, 3L, 3L, 4L, 2L, 1L, 2L, 5L, 2L, 
1L, 6L, 3L, 7L, 3L, 2L, 1L, 4L, 3L, 2L), y = c(1L, 1L, 1L, 1L, 
2L, 1L, 1L, 1L, 2L, 1L, 1L, 2L, 1L, 3L, 1L, 1L, 1L, 2L, 1L, 1L
), z = c(1L, 2L, 3L, 3L, 1L, 2L, 1L, 2L, 2L, 2L, 1L, 3L, 3L, 
1L, 3L, 2L, 1L, 1L, 3L, 2L)), .Names = c("x", "y", "z"), class = "data.frame", row.names = c(NA, 
-20L))

我可以编写一个带有多个if语句的for循环来逐行填充yz。这看起来并非如此:它没有矢量化。是否有方法指定哪些数值将对应于新的数值?像地图或键一样,用于指示哪些值将基于之前的值。

1 个答案:

答案 0 :(得分:2)

解决方案#1:查找向量

假设我在评论中指出的不匹配是数据中的错误,而不是规则中的错误,那么您可以按如下方式完成此操作:

x2y <- rep(1:3,each=3);
x2z <- rep(1:3,3);
df$y <- x2y[df$x];
df$z <- x2z[df$x];
df1 <- df; ## for identical() calls later
df;
##    x y z
## 1  1 1 1
## 2  2 1 2
## 3  3 1 3
## 4  3 1 3
## 5  4 2 1
## 6  2 1 2
## 7  1 1 1
## 8  2 1 2
## 9  5 2 2
## 10 2 1 2
## 11 1 1 1
## 12 6 2 3
## 13 3 1 3
## 14 7 3 1
## 15 3 1 3
## 16 2 1 2
## 17 1 1 1
## 18 4 2 1
## 19 3 1 3
## 20 2 1 2

上述解决方案取决于x的域由从1开始的连续整数值组成的事实,因此直接索引到&#34;查找向量&#34;就足够了。如果x以非常高的数字开始但仍然是连续的,则可以通过在编制索引之前减去一个小于x的最小值来使此解决方案有效。

解决方案#2:查找表

如果您不喜欢这个假设,那么您可以使用查找表完成任务:

library('data.table');
lookup <- data.table(x=1:9,y=x2y,z=x2z,key='x');
lookup;
##    x y z
## 1: 1 1 1
## 2: 2 1 2
## 3: 3 1 3
## 4: 4 2 1
## 5: 5 2 2
## 6: 6 2 3
## 7: 7 3 1
## 8: 8 3 2
## 9: 9 3 3
df[c('y','z')] <- lookup[df['x'],.(y,z)];
identical(df,df1);
## [1] TRUE

或基础R方法:

lookup <- data.frame(x=1:9,y=x2y,z=x2z);
lookup;
##   x y z
## 1 1 1 1
## 2 2 1 2
## 3 3 1 3
## 4 4 2 1
## 5 5 2 2
## 6 6 2 3
## 7 7 3 1
## 8 8 3 2
## 9 9 3 3
df[c('y','z')] <- lookup[match(df$x,lookup$x),c('y','z')];
identical(df,df1);
## [1] TRUE

解决方案#3:算术表达式

另一种替代方法是设计与映射等效的算术表达式:

df$y <- (df$x-1L)%/%3L+1L;
df$z <- 3L--df$x%%3L;
identical(df,df1);
## [1] TRUE

这个特殊的解决方案取决于你的映射恰好具有适用于算术描述的规律性这一事实。

关于实现,它还利用R precedence rules的一些非显而易见的属性(实际上其他语言也是如此,例如C/C++和{{3} }),即一元负数高于模数,高于二元减法,因此df$z的计算相当于3L-((-df$x)%%3L)

关于z计算的更多细节:不可能用df$x%%3的直模来描述映射,因为3,6和9输入将修改为零。这可以通过简单的索引分配操作来解决,但我想实现一个更简单和纯粹的算术解决方案。要从0到3,我们可以从3减去df$x%%3,但这会弄乱(反转)剩余的值。我意识到通过获取输入值的的mod,我们将&#34; pre-invert&#34;他们,然后从3中减去所有这些&#34;对&#34;它们也会根据需要将零转换为3。