在ifelse()内部提取时引用列

时间:2017-05-13 10:35:32

标签: r if-statement

我有一个包含性别,年龄和原始分数的数据框(“dat”)以及两个表(“m”,“f”),每个性别一个,其中包含按原始分数排序的t值(行)和年龄(列):

dat <- data.frame(code = c("A01", "B02"), sex = c("f", "m"), age = c(6, 8), raw.score = c(12, 5))

m <- read.table(textConnection("
36 32 36 33 20 33 32 20 31 33 35 43
38 36 41 40 36 41 36 30 34 40 39 43
42 42 43 42 40 43 38 36 40 44 41 43
42 43 43 46 44 45 41 42 44 45 43 44
43 46 44 47 46 46 44 45 47 49 46 48
44 47 48 47 49 49 45 48 47 50 50 48
45 49 49 48 50 49 45 50 49 51 51 53
47 51 49 50 50 51 46 51 51 55 54 53
51 54 51 51 52 52 49 53 53 57 57 53
54 55 54 52 53 54 51 53 54 60 57 55
55 58 55 55 55 56 52 56 56 60 57 56
55 58 56 55 57 58 53 58 57 61 59 57
56 61 56 56 59 58 54 59 58 61 63 59
57 62 58 57 60 58 55 59 62 62 63 59
58 63 59 58 64 61 58 62 62 63 63 61
60 64 59 60 64 62 59 63 62 63 69 63
62 64 60 61 66 62 59 64 62 63 69 63
62 64 60 62 69 63 61 65 64 63 69 63
62 64 60 64 69 65 62 67 64 65 73 63
62 68 61 65 69 65 62 70 66 67 73 67
62 68 66 65 69 65 63 70 66 70 73 67
62 70 66 65 69 65 64 70 66 70 73 67
64 70 66 67 69 65 65 73 66 70 73 67
64 70 69 73 69 67 66 73 66 70 73 73
64 70 73 73 69 70 66 73 66 73 73 73
68 70 73 73 69 70 68 73 73 73 73 73
68 73 73 73 73 73 70 73 73 73 73 73
73 73 73 73 73 73 73 73 73 73 73 73
73 73 73 73 73 73 73 73 73 73 73 73
73 73 73 73 73 73 73 73 73 73 73 73
73 73 73 73 73 73 73 73 73 73 73 73
"), header = FALSE)

f <- read.table(textConnection("
32 34 34 34 38 34 34 37 37 20 20 41
32 39 36 34 38 37 38 39 37 32 36 42
41 45 41 47 41 38 40 42 40 40 43 45
44 47 47 47 47 40 44 45 40 46 49 49
47 49 49 50 48 42 46 50 44 48 50 53
48 52 50 50 52 45 48 52 47 48 50 55
51 52 51 51 54 47 49 54 49 51 51 58
53 57 51 53 55 48 50 55 51 53 55 59
54 60 56 54 55 50 50 59 51 56 56 59
55 61 56 56 59 51 51 60 51 56 60 62
56 61 57 58 60 52 54 62 53 60 60 64
59 64 61 58 62 52 56 62 55 60 73 64
59 64 61 59 62 53 58 62 56 62 73 64
59 66 63 59 62 55 59 63 56 62 73 64
62 69 66 60 65 56 59 63 56 62 73 66
62 69 66 60 69 57 59 67 56 62 73 66
62 73 69 62 69 58 60 67 56 64 73 66
62 73 69 62 69 60 60 67 58 64 73 73
62 73 73 63 69 62 60 67 58 64 73 73
62 73 73 66 69 64 63 69 60 64 73 73
62 73 73 69 69 64 66 69 60 64 73 73
64 73 73 69 69 66 68 69 60 68 73 73
64 73 73 69 69 66 68 69 63 68 73 73
64 73 73 69 73 68 70 69 63 68 73 73
68 73 73 69 73 68 70 69 66 68 73 73
73 73 73 69 73 68 70 69 66 68 73 73
73 73 73 73 73 70 73 73 66 68 73 73
73 73 73 73 73 70 73 73 73 68 73 73
73 73 73 73 73 70 73 73 73 73 73 73
73 73 73 73 73 70 73 73 73 73 73 73
73 73 73 73 73 73 73 73 73 73 73 73
"), header = FALSE)

我想查找表中的t值,并将它们作为列添加到数据框中。正确的结果数据框应如下所示:

> dat
  code sex age raw.score t.value
1  A01   f   6        12      52
2  B02   m   8         5      45

我尝试了以下内容:

dat$t.value <- ifelse(
                      dat$sex == "m",
                      m[dat$raw.score, dat$age],
                      f[dat$raw.score, dat$age]
                     )

但这不起作用。我原本期望以下内容:

> ifelse(
+        dat$sex == "m",
+        m[5, 8],
+        f[12, 6]
+       )
[1] 52 45

[dat$raw.score, dat$age]调用整列,而不是仅调用相关行:

> ifelse(
+        dat$sex == "m",
+        m[dat$raw.score, dat$age],
+        f[dat$raw.score, dat$age]
+       )
[[1]]
[1] 52 42

[[2]]
[1] 58 45

如何将[dat$raw.score, dat$age]中的索引仅限制为“dat”的相关行?

我的实际代码比上面的例子更复杂。它包含几个嵌套的ifelse(),所以我不能轻易地用另一个结构替换该部分。

后续问题

我正在使用@ akrun与mapply()的解决方案。在我的真实数据中,有许多原始分数列(“raw.score.1”,“raw.score.2”,...),所有这些都必须在许多相应的表中查找t值(“m.1”,“f.1”,“m.2”,“f.2”,......)。因此,我想重用mapply()应用于数据的函数,而不必为每个变量重新键入它。

这是一个更新的示例代码,显示了我想要做的事情(最后):

# data frame with data
dat <- data.frame(code = c("A01", "B02"), sex = c("f", "m"), age = c(6, 8), raw.score.1 = c(12, 5), raw.score.2 = c(6, 3))

# t-values for first raw score
m.1 <- read.table(textConnection("
36 32 36 33 20 33 32 20 31 33 35 43
38 36 41 40 36 41 36 30 34 40 39 43
42 42 43 42 40 43 38 36 40 44 41 43
42 43 43 46 44 45 41 42 44 45 43 44
43 46 44 47 46 46 44 45 47 49 46 48
44 47 48 47 49 49 45 48 47 50 50 48
45 49 49 48 50 49 45 50 49 51 51 53
47 51 49 50 50 51 46 51 51 55 54 53
51 54 51 51 52 52 49 53 53 57 57 53
54 55 54 52 53 54 51 53 54 60 57 55
55 58 55 55 55 56 52 56 56 60 57 56
55 58 56 55 57 58 53 58 57 61 59 57
"), header = FALSE)

f.1 <- read.table(textConnection("
32 34 34 34 38 34 34 37 37 20 20 41
32 39 36 34 38 37 38 39 37 32 36 42
41 45 41 47 41 38 40 42 40 40 43 45
44 47 47 47 47 40 44 45 40 46 49 49
47 49 49 50 48 42 46 50 44 48 50 53
48 52 50 50 52 45 48 52 47 48 50 55
51 52 51 51 54 47 49 54 49 51 51 58
53 57 51 53 55 48 50 55 51 53 55 59
54 60 56 54 55 50 50 59 51 56 56 59
55 61 56 56 59 51 51 60 51 56 60 62
56 61 57 58 60 52 54 62 53 60 60 64
59 64 61 58 62 52 56 62 55 60 73 64
"), header = FALSE)

# t-values for second raw score
m.2 <- read.table(textConnection("
32 32 34 30 37 40 36 33 38 38 42 44
40 38 36 36 41 44 41 38 42 44 45 47
43 40 40 40 44 48 44 43 46 46 49 51
43 43 42 41 44 50 46 46 49 48 54 52
43 45 42 44 47 52 47 51 49 49 54 53
43 47 44 46 48 54 50 52 50 53 56 55
44 47 46 49 49 55 51 53 52 53 58 55
46 50 48 50 49 56 53 54 55 54 58 55
46 50 49 50 50 57 54 56 56 56 59 55
46 53 51 51 51 57 54 56 56 57 60 55
47 54 51 52 52 58 56 58 58 60 60 56
48 54 54 54 52 59 60 60 60 61 63 57
"), header = FALSE)

f.2 <- read.table(textConnection("
36 36 39 37 42 40 40 41 34 40 43 45
38 36 40 42 46 44 43 46 40 46 47 49
40 40 43 44 48 46 46 51 44 49 47 53
42 46 44 47 50 47 48 52 44 51 50 53
42 46 47 48 52 49 49 54 51 53 52 55
45 49 48 50 57 50 50 57 53 56 56 58
45 49 49 50 59 54 51 58 55 56 57 60
47 52 51 50 62 55 53 59 56 56 57 60
50 53 53 51 62 56 55 60 60 56 64 60
50 54 55 51 62 57 56 62 60 58 68 62
53 54 56 52 63 58 56 65 60 60 68 63
56 59 59 54 65 59 57 65 63 60 73 63
"), header = FALSE)

# t-values can be inserted by repeating @acrun's solution
dat$t.1 <- mapply(function(x, y, z) ifelse(x=="m", m.1[y, z], f.1[y, z]),
                  dat$sex, dat$raw.score.1, dat$age)
dat$t.2 <- mapply(function(x, y, z) ifelse(x=="m", m.2[y, z], f.2[y, z]),
                  dat$sex, dat$raw.score.2, dat$age)

# the result looks as it should
dat
#   code sex age raw.score.1 raw.score.2 t.1 t.2
# 1  A01   f   6          12           6  52  50
# 2  B02   m   8           5           3  45  43

# let's delete the columns with the t-values
dat$t.1 <- NULL
dat$t.2 <- NULL

# and try to define a function outsife of mapply()
t.fun <- function(v, w, x, y, z) ifelse(x=="m", v[y, z], w[y, z])

# but mapply() reduces the t-value tables to one row, too
dat$t.1 <- mapply(t.fun,
                  m.1, f.1, dat$sex, dat$raw.score.1, dat$age)
# Error in w[y, z] : incorrect number of dimensions

dat$t.2 <- mapply(t.fun,
                  m.2, f.2, dat$sex, dat$raw.score.2, dat$age)
# Error in w[y, z] : incorrect number of dimensions

2 个答案:

答案 0 :(得分:1)

您需要使用类似sapply ...

的内容逐行循环
dat$t.value <- sapply(1:nrow(dat),function(i) ifelse(dat$sex[i] == "m",
                                           m[dat$raw.score[i], dat$age[i]],
                                           f[dat$raw.score[i], dat$age[i]]))

dat
  code sex age raw.score  t
1  A01   f   6        12 52
2  B02   m   8         5 45

答案 1 :(得分:1)

我们可以使用mapply/Map

dat$t.value <- mapply(function(x, y, z) ifelse(x=="m", m[y, z], f[y, z]), 
              dat$sex, dat$raw.score, dat$age)
dat$t.value
#[1] 52 45

但是,这可以通过创建索引('i1')然后根据逻辑索引分配值来进行矢量化

i1 <- dat$sex=="m"
dat$t.value[i1] <- m[dat$raw.score[i1], dat$age[i1]]
dat$t.value[!i1] <- f[dat$raw.score[!i1], dat$age[!i1]]
dat 
#  code sex age raw.score t.value
#1  A01   f   6        12      52
#2  B02   m   8         5      45