我在替换数据框中的值时遇到了一些麻烦。我想基于单独的表替换值。以下是我想要做的一个例子。
我有一张桌子,每排都是顾客,每列都是他们购买的动物。让我们调用此数据框|data startTag tag|.
data := '123456778'
startTag := false.
tag := ''.
data asArray do: [:char |
tag := tag,char]
。
table
我还有一个名为> table
# P1 P2 P3
# 1 cat lizard parrot
# 2 lizard parrot cat
# 3 parrot cat lizard
的表格。
lookUp
我想要做的是创建一个名为> lookUp
# pet class
# 1 cat mammal
# 2 lizard reptile
# 3 parrot bird
的新表,其中一个函数将new
中的所有值替换为table
中的class
列。我自己尝试使用lookUp
函数,但是我收到了以下警告。
lapply
有关如何使这项工作的任何想法?
答案 0 :(得分:29)
你在问题中发布了一个不错的方法。这是一种熟悉的方法:
new <- df # create a copy of df
# using lapply, loop over columns and match values to the look up table. store in "new".
new[] <- lapply(df, function(x) look$class[match(x, look$pet)])
更快的另一种方法是:
new <- df
new[] <- look$class[match(unlist(df), look$pet)]
请注意,我在两种情况下都使用空括号([]
)来保持new
的结构(data.frame)。
(我在答案中使用df
代替table
和look
代替lookup
答案 1 :(得分:19)
其他选项是tidyr
和dplyr
library(dplyr)
library(tidyr)
table %>%
gather(key = "pet") %>%
left_join(lookup, by = "pet") %>%
spread(key = pet, value = class)
答案 2 :(得分:11)
如果您有两个单独的data.frame
并且正在尝试将信息从一个传递到另一个,那么答案就是 merge 。
每个人都有自己喜欢的合并方法。我的是data.table
。
此外,由于您要对许多列执行此操作,melt
和dcast
的速度会更快 - 而不是循环遍历列,将其应用到重新整形的表中,然后重新整形试。
library(data.table)
#the row names will be our ID variable for melting
setDT(table, keep.rownames = TRUE)
setDT(lookUp)
#now melt, merge, recast
# melting (reshape wide to long)
table[ , melt(.SD, id.vars = 'rn')
# merging
][lookup, new_value := i.class, on = c(value = 'pet')
#reform back to original shape
][ , dcast(.SD, rn ~ variable, value.var = 'new_value')]
# rn P1 P2 P3
# 1: 1 mammal reptile bird
# 2: 2 reptile bird mammal
# 3: 3 bird mammal reptile
如果您发现dcast
/ melt
位有点令人生畏,这里的方法只是循环遍历列; dcast
/ melt
只是回避了这个问题的循环。
setDT(table) #don't need row names this time
setDT(lookUp)
sapply(names(table), #(or to whichever are the relevant columns)
function(cc) table[lookUp, (cc) := #merge, replace
#need to pass a _named_ vector to 'on', so use setNames
i.class, on = setNames("pet", cc)])
答案 3 :(得分:5)
创建一个命名向量,并循环遍历每一列并匹配,请参阅:
# make lookup vector with names
lookUp1 <- setNames(as.character(lookUp$class), lookUp$pet)
lookUp1
# cat lizard parrot
# "mammal" "reptile" "bird"
# match on names get values from lookup vector
res <- data.frame(lapply(df1, function(i) lookUp1[i]))
# reset rownames
rownames(res) <- NULL
# res
# P1 P2 P3
# 1 mammal reptile bird
# 2 reptile bird mammal
# 3 bird mammal reptile
df1 <- read.table(text = "
P1 P2 P3
1 cat lizard parrot
2 lizard parrot cat
3 parrot cat lizard", header = TRUE)
lookUp <- read.table(text = "
pet class
1 cat mammal
2 lizard reptile
3 parrot bird", header = TRUE)
答案 4 :(得分:1)
我是使用内置的 factor
完成的。
table$P1 <- factor(table$P1, levels=lookUp$pet, labels=lookUp$class)
table$P2 <- factor(table$P2, levels=lookUp$pet, labels=lookUp$class)
table$P3 <- factor(table$P3, levels=lookUp$pet, labels=lookUp$class)
答案 5 :(得分:0)
在dplyr中显示如何执行此操作的答案above无法回答问题,表中填充了NA。这有效,我将不胜感激任何评论显示更好的方式:
# Add a customer column so that we can put things back in the right order
table$customer = seq(nrow(table))
classTable <- table %>%
# put in long format, naming column filled with P1, P2, P3 "petCount"
gather(key="petCount", value="pet", -customer) %>%
# add a new column based on the pet's class in data frame "lookup"
left_join(lookup, by="pet") %>%
# since you wanted to replace the values in "table" with their
# "class", remove the pet column
select(-pet) %>%
# put data back into wide format
spread(key="petCount", value="class")
请注意,保留包含客户,宠物,宠物物种(?)及其类别的长桌可能很有用。此示例只是将中间保存添加到变量:
table$customer = seq(nrow(table))
petClasses <- table %>%
gather(key="petCount", value="pet", -customer) %>%
left_join(lookup, by="pet")
custPetClasses <- petClasses %>%
select(-pet) %>%
spread(key="petCount", value="class")
答案 6 :(得分:0)
我尝试了其他方法,但是我的大型数据集花了很长时间。我改为使用以下内容:
# make table "new" using ifelse. See data below to avoid re-typing it
new <- ifelse(table1 =="cat", "mammal",
ifelse(table1 == "lizard", "reptile",
ifelse(table1 =="parrot", "bird", NA)))
此方法要求您为代码编写更多文本,但是ifelse
的矢量化使其运行更快。您必须根据数据决定是否要花费更多时间编写代码或等待计算机运行。如果要确保它有效(iflese
命令中没有任何错字),可以使用apply(new, 2, function(x) mean(is.na(x)))
。
数据
# create the data table
table1 <- read.table(text = "
P1 P2 P3
1 cat lizard parrot
2 lizard parrot cat
3 parrot cat lizard", header = TRUE)