使用示例数据框:
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。
有没有办法从数字列表中重新编码列而无需依次遍历每个数字?我通常使用重新编码功能,但我不确定如何使用大型列表执行此操作。
任何帮助将不胜感激。
答案 0 :(得分: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
的5倍。此外,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
答案 1 :(得分: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 Why doesn't R think these numbers are equal?。处理此问题的一种方法是将用于合并的列设置为类“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)
可能的合并解决方案:join
包中的plyr
“与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
来自?join
:“Join
通常比merge
更快”。这是否是这种情况,以及它是否比match
更快,我会留给其他人展示。
答案 2 :(得分: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]])
答案 3 :(得分:1)
我喜欢@Henrik的merge
解决方案,它似乎清晰易用。
我采用factor
的方式,虽然我不认为转换回数字的过程非常优雅。使用cut
的@ hadley解决方案类似。
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))))
答案 4 :(得分: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
答案 5 :(得分: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
由于所有操作都是矢量化的,因此长列表应该相当快。
答案 6 :(得分: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
最后一步是将a
中的值与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]
这样就可以了。