3

使用示例数据框:

df <- structure(list(KY27SCH1 = c(4, 4, 4, 4, NA, 5, 2, 4, 4, NA, 4, 
                                  5, 3, 5, 5), KY27SCH2 = c(5, 4, 4, 4, NA, 4, 1, 4, 4, NA, 4, 
                                                            5, 4, 5, 5), KY27SCH3 = c(4, 4, 5, 4, NA, 4, 4, 4, 5, NA, 5, 
                                                                                      5, 3, 5, 5), KY27SCH4 = c(3, 5, 5, 4, NA, 5, 4, 5, 5, NA, 5, 
                                                                                                                5, 4, 5, 5)), .Names = c("KY27SCH1", "KY27SCH2", "KY27SCH3", 
                                                                                                                                         "KY27SCH4"), row.names = 197:211, class = "data.frame")

在将此新列绑定到原始数​​据框之前,我应用了一行代码将四个不同的列添加在一起:

KC27sc_R <- rowSums(df[, c("KY27SCH1", "KY27SCH2", "KY27SCH3", "KY27SCH4")], na.rm = TRUE)
df <- cbind(df, KC27sc_R) # Adds columns to survey dataframe

然后我想使用下面详述的结果表重新编码变量 KC27sc_R:

5= -4.287
6 = -3.040
7 = -2.405
8 = -1.960
9 = -1.605
10 = -1.296
11 = -1.011
12 = -0.735
13 = -0.456
14 = -0.168
15 = 0.134
16 = 0.454
17 = 0.796
18 = 1.166
19 = 1.574
20 = 2.035
21 = 2.582
22 = 3.299 
23 = 4.594

即 KC27sc_R 列中的 5 将变为 -4.287。

有没有一种方法可以从数字列表中重新编码一列,而不必依次遍历每个数字?我通常使用重新编码功能,但我不确定如何使用大列表执行此操作。

任何帮助,将不胜感激。

4

7 回答 7

7

假设我们已将您的查找表设置为data.frame如下所示:

mydf <- structure(list(V1 = c(5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 
    16, 17, 18, 19, 20, 21, 22, 23), V2 = c(-4.287, -3.04, -2.405, 
    -1.96, -1.605, -1.296, -1.011, -0.735, -0.456, -0.168, 0.134, 
    0.454, 0.796, 1.166, 1.574, 2.035, 2.582, 3.299, 4.594)), .Names = c("V1", 
    "V2"), class = "data.frame", row.names = c(NA, -19L))
mydf
#    V1     V2
# 1   5 -4.287
# 2   6 -3.040
# 3   7 -2.405
# 4   8 -1.960
# 5   9 -1.605
# 6  10 -1.296
# 7  11 -1.011
# 8  12 -0.735
# 9  13 -0.456
# 10 14 -0.168
# 11 15  0.134
# 12 16  0.454
# 13 17  0.796
# 14 18  1.166
# 15 19  1.574
# 16 20  2.035
# 17 21  2.582
# 18 22  3.299
# 19 23  4.594

您应该能够使用以下内容来获取您正在寻找的内容:

df$RECODED <- mydf$V2[match(as.character(df$KC27sc_R), as.character(mydf$V1))]
df
#     KY27SCH1 KY27SCH2 KY27SCH3 KY27SCH4 KC27sc_R RECODED
# 197        4        5        4        3       16   0.454
# 198        4        4        4        5       17   0.796
# 199        4        4        5        5       18   1.166
# 200        4        4        4        4       16   0.454
# 201       NA       NA       NA       NA        0      NA
# 202        5        4        4        5       18   1.166
# 203        2        1        4        4       11  -1.011
# 204        4        4        4        5       17   0.796
# 205        4        4        5        5       18   1.166
# 206       NA       NA       NA       NA        0      NA
# 207        4        4        5        5       18   1.166
# 208        5        5        5        5       20   2.035
# 209        3        4        3        4       14  -0.168
# 210        5        5        5        5       20   2.035
# 211        5        5        5        5       20   2.035

其中的as.character一部分是帮助缓解潜在的 FP 问题。


这在概念上与已提供的解决方案非常相似merge,但可能要快得多。

在人工数据集上进行基准测试:

set.seed(1)
df <- data.frame(matrix(sample(0:25, 100000, replace = TRUE), ncol = 2))

library(microbenchmark)
microbenchmark(
  A = {
    df2 <- merge(df, mydf, by.x="X1", by.y="V1", sort = FALSE)
  },
  B = {
    df3 <- cbind(df, recoded = mydf$V2[match(as.character(df$X1), 
                                             as.character(mydf$V1))])
  }
)
Unit: milliseconds
#  expr       min        lq    median       uq       max neval
#     A 141.32530 149.61354 154.99230 162.7845 239.26242   100
#     B  24.93267  25.32541  25.73723  26.0792  96.44209   100

基本匹配方法的速度是merge. 此外,merge倾向于对您的行排序做一些时髦的事情。比较原始数据集的前几行 ( df)、合并后的数据 ( )df2和我的解决方案 ( df3)。正如你所看到的,merge已经完全重新排列了data.frame,即使我们已经指定了 " sort = FALSE"。

head(df)
#   X1 X2
# 1  6 15
# 2  9 18
# 3 14  8
# 4 23  3
# 5  5 22
# 6 23  1
head(df2)
#   X1 X2    V2
# 1  6 15 -3.04
# 2  6 23 -3.04
# 3  6  3 -3.04
# 4  6  0 -3.04
# 5  6 20 -3.04
# 6  6 16 -3.04
head(df3)
#   X1 X2 recoded
# 1  6 15  -3.040
# 2  9 18  -1.605
# 3 14  8  -0.168
# 4 23  3   4.594
# 5  5 22  -4.287
# 6 23  1   4.594
于 2013-08-27T17:19:27.737 回答
3

如果您将重新编码值保存在第二个数据框中,您可以尝试merge

# original data
df <- data.frame(x = sample(5:7, 10, replace = TRUE))

# recoding data
df2 <- data.frame(x = 5:7, new_x = c(-4.287, -3.040, -2.405))

merge(df, df2)

按照@hadley 的评论进行编辑

上面的解决方案是测试浮点数是否相等,这不是一种可靠的方法,请参阅R FAQ 7.31 为什么 R 认为这些数字不相等?. 处理此问题的一种方法是设置用于合并到类“ integer”的列。(我注意到在最后一个示例中没有考虑这个潜在问题?merge

# original data
df <- data.frame(x = as.integer(sample(5:7, 10, replace = TRUE)))

# recoding data
df2 <- data.frame(x = as.integer(5:7), new_x = c(-4.287, -3.040, -2.405))

merge(df, df2)

按照@Ananda Mahto 的评论进行编辑 - 使用 NA 的合并和处理进行时髦排序

# original data with NA
df <- data.frame(x = as.integer(c(7, NA, 5, 6, NA, 5)))

# recoding data as above, without NA
merge(df, df2, sort = FALSE)
# 'unspecified' order and no match with NA

# can at least handle NA by including NA also in recoding data
df2 <- data.frame(x = as.integer(c(5:7, NA)), new_x = c(-4.287, -3.040, -2.405, NA))
merge(df, df2, sort = FALSE)

一个可能的merge-oid解决方案:joinplyr
中 “Unlike merge,无论使用什么连接类型都join 保留x的顺序”,并且在重新编码数据时不需要NA。

library(plyr)
df <- data.frame(x = as.integer(c(7, NA, 5, 6, NA, 5)))
df2 <- data.frame(x = as.integer(c(5:7)), new_x = c(-4.287, -3.040, -2.405))
join(df, df2)
# looks OK

From ?join: "Join通常比merge" 快。这里是否是这样,是否比 快match,我留给别人展示。

于 2013-08-23T12:32:55.343 回答
1

对于初学者,假设您的结果表存储在矩阵中yo

yo <- matrix(0, nrow = 19, ncol = 2)
yo[, 1] <- c(5:23)
yo[, 2] <- c( -4.287, -3.040, -2.405, -1.960, -1.605, -1.296, -1.011, -0.735, -0.456, -0.168, 0.134, 0.454, 0.796, 1.166, 1.574, 2.035, 2.582, 3.299, 4.594)

即,第一列yo对应于您要更改的值,第二列对应于您要更改的值。简而言之,将yo其视为一个函数 - 第一列是该函数的x变量,第二列是函数的输出。

您需要弄清楚的第一件事是实际存在 KC27sc_R 值的索引yo[, 1](在哪些行中您实际上可以用新值替换旧值)。这样做是这样的:

ind <- which( df$KC27sc_R %in% yo[,1] )

ind为您提供可以更改的 KC27sc_R 的所有值的行。下一步是获取所有这些值:

a <- df[ind,]$KC27sc_R

最后一步是将 in 的值a与 in的值联系起来yo[, 1]——从字面上找到yo[, 1]可以在其中找到每个相应值的行a——函数match在这里会很有帮助:

b <- match( a, yo[,1] )

就像ind,b是一个索引 - 对于 中的每个值a,它会告诉您yo[, 2]需要去哪一行才能找到该值的替换a。最后一步是替换您的值df

df[ind, "KC27sc_R"] <- yo[b, 2]

那会成功的。

于 2013-09-01T01:58:09.273 回答
1

需要最少打字且可移植的答案:

# Your original values
origval = seq(5,23)
newval = c(-4.287, -3.04, -2.405, -1.96, -1.605, -1.296, -1.011, -0.735, -0.456, -0.168, 0.134, 0.454, 0.796, 1.166, 1.574, 2.035, 2.582, 3.299, 4.594)

# generate a relationship
sp = smooth.spline(origval,newval)

# look up a value based on your original sequence
pval = predict(sp, origval)

现在pval$y将包含预测(转换)点。

您可以将任何其他值集以任何顺序predict放置在函数中origval,甚至那些不在数据系列中的值(5.5 等)

应用于您的数据集,您可以为变量创建一个占位符,然后“预测”其值:

df$KY_Rnew = df$KC27sc_R
df$KY_Rnew[!is.na(df$KY_Rnew)] = predict(sp,df$KY_Rnew[!is.na(df$KY_Rnew)])$y
于 2013-08-27T20:40:23.210 回答
1

假设您的映射值都是整数,您可以在映射值的位置创建一个包含编码值的向量:

# using mydf defined by Ananda Mahto:
mydf <- structure(list(V1 = c(5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 
 16, 17, 18, 19, 20, 21, 22, 23), V2 = c(-4.287, -3.04, -2.405, 
 -1.96, -1.605, -1.296, -1.011, -0.735, -0.456, -0.168, 0.134, 
 0.454, 0.796, 1.166, 1.574, 2.035, 2.582, 3.299, 4.594)), .Names = c("V1", 
 "V2"), class = "data.frame", row.names = c(NA, -19L))

# create vector with index positions corresponding to objective values:
vmap <- rep(NA, length=max(mydf$V1)) 
vmap[mydf$V1] <- mydf$V2

vmap
# [1]     NA     NA     NA     NA -4.287 -3.040 -2.405 -1.960 -1.605 -1.296
# [11] -1.011 -0.735 -0.456 -0.168  0.134  0.454  0.796  1.166  1.574  2.035
# [21]  2.582  3.299  4.594

# Assign NA to zero values in KC27sc_R (as you cannot have a zero position in a R vector)
# (this could also be another value defined in mydf if you want zero to map to something)
KC27sc_R[KC27sc_R==0] <- NA

# Then, select the values in vmap using the indices defined in KC27sc_R:
Krecode <- vmap[KC27sc_R]
data.frame(KC27sc_R, Krecode)


# KC27sc_R Krecode
# 197       16   0.454
# 198       17   0.796
# 199       18   1.166
# 200       16   0.454
# 201       NA      NA
# 202       18   1.166
# ... etc

由于所有操作都是矢量化的,因此这应该相当快,因为​​列表很长。

于 2013-08-27T23:22:33.047 回答
1

我喜欢@Henrik 的merge解决方案,它看起来清晰且易于使用。

我采用了 using 的方式factor,尽管我不认为转换回数字的过程非常优雅。@hadley 的解决方案使用cut类似。

df = data.frame(x = sample(5:7, 10, replace = TRUE))
# Using factor(), to convert to numeric have to go through a character
df$y = as.numeric(as.character(factor(df$x, labels = c(-4.287, -3.040, -2.405))))

# Using cut() is similar to factor, need to use the breaks argument
df$z = as.numeric(as.character(cut(df$x, breaks = 3, labels = c(-4.287, -3.040, -2.405))))
于 2013-08-27T15:15:42.250 回答
1

我不是百分百确定你的问题是对的。但我认为您要问的是:您有一个从整数到值的映射,并且您想用映射中指定的值替换数据框(或向量)中的所有整数。

我会将映射放在一个列表中:

code = list()
code[[5 ]] = -4.287
code[[6 ]] = -3.040
code[[7 ]] = -2.405
code[[8 ]] = -1.960
code[[9 ]] = -1.605
code[[10]] = -1.296
code[[11]] = -1.011
code[[12]] = -0.735
code[[13]] = -0.456
code[[14]] = -0.168
code[[15]] = 0.134
code[[16]] = 0.454
code[[17]] = 0.796
code[[18]] = 1.166
code[[19]] = 1.574
code[[20]] = 2.035
code[[21]] = 2.582
code[[22]] = 3.299 
code[[23]] = 4.594

然后使用 apply (或 sapply for vector)进行替换:

apply(df, c(1,2), function(x) code[[x]])
于 2013-08-27T13:29:41.897 回答