使用 R 中的散列 table/dictionary 将键列替换为值
Replace key column with values using a hash table/dictionary in R
我想合并两个基于多个列的数据框。这里基于 df1 中的 B 列和 df2 中 X-Z 的所有列,但将 X 列的值返回到 V1。
像字典一样,如果 df1$B 中的 a 与 df2$X 中的 a 匹配,则将 a 返回到 df_merged$V1,但是如果 df1$B 中的 c 与 df2$Y 匹配,则从 df2 返回 b $X,是它的同义词等等。只有df2$X可以返回到df_merged$V1
df1
A B
1 a
2 c
3 f
和 df2
X Y Z
a NA NA
b c NA
d e f
merged_df
A V1
1 a
2 b
3 d
这是我的尝试:
merge(df1, df2, by.x="B", by.y=c("X", "Y", "Z"), all.x=T)
您通常可以使用 tidyverse
来执行此操作,或者您实际上可以使用 hash/dictionary-like 数据结构。在 R 中,没有原生散列 table class,但您可以利用 hashmap
包,它在内部使用 Rcpp
来创建类似散列的对象:
library(tidyverse)
library(hashmap)
dict = df2 %>%
mutate_if(is.factor, as.character) %>%
mutate(Value = X) %>%
gather(Label, Key, -Value) %>%
na.omit() %>%
{hashmap(.$Key, .$Value)}
这给你一个散列 table:
> dict
## (character) => (character)
## [e] => [d]
## [d] => [d]
## [f] => [d]
## [b] => [b]
## [a] => [a]
现在,要使用 df1$B
作为键提取值,只需执行以下操作:
dict[[df1$B]]
# [1] "a" NA "a" "d"
df1 %>%
mutate(Value = dict[[B]]) %>%
na.omit() %>%
select(-B)
结果:
A Value
1 1 a
3 3 a
4 4 d
数据:
df1 = read.table(text = "A B
1 a
2 c
3 a
4 e", header = TRUE, stringsAsFactors = TRUE)
df2 = read.table(text = "X Y Z
a NA NA
b NA NA
d e f", header = TRUE, stringsAsFactors = TRUE)
这是用于演示目的的通用版本,但此方法不如使用 hashmap
:
健壮、灵活且效率低
library(tidyverse)
df2 %>%
mutate(Value = X) %>%
gather(Label, Key, -Value) %>%
split(.$Label) %>%
map_dfr(~ cbind(A = na.omit(match(.$Key, df1$B)),
slice(., match(df1$B, .$Key)))) %>%
select(A, Value) %>%
arrange(A)
结果:
A Value
1 1 a
2 3 d
3 4 d
数据:
df1 = read.table(text = "A B
1 a
2 c
3 f
4 e", header = TRUE, stringsAsFactors = FALSE)
df2 = read.table(text = "X Y Z
a NA NA
b NA NA
d e f", header = TRUE, stringsAsFactors = FALSE)
注:
我首先复制了 df2$X
因为它在技术上也是一把钥匙。然后,我将 df2
重塑为长格式,并将 split
重塑为 Key
。对于每个键,我 sliced
与 df2$B
匹配的行,并将结果与 map_dfr
一起 rbind
。最后,只返回 Value
列。
请注意,我在此示例中使用了与 hashmap
示例中不同的 df1
,因为如果 df1$B
有重复项,此方法将不起作用。
我想合并两个基于多个列的数据框。这里基于 df1 中的 B 列和 df2 中 X-Z 的所有列,但将 X 列的值返回到 V1。 像字典一样,如果 df1$B 中的 a 与 df2$X 中的 a 匹配,则将 a 返回到 df_merged$V1,但是如果 df1$B 中的 c 与 df2$Y 匹配,则从 df2 返回 b $X,是它的同义词等等。只有df2$X可以返回到df_merged$V1
df1
A B
1 a
2 c
3 f
和 df2
X Y Z
a NA NA
b c NA
d e f
merged_df
A V1
1 a
2 b
3 d
这是我的尝试:
merge(df1, df2, by.x="B", by.y=c("X", "Y", "Z"), all.x=T)
您通常可以使用 tidyverse
来执行此操作,或者您实际上可以使用 hash/dictionary-like 数据结构。在 R 中,没有原生散列 table class,但您可以利用 hashmap
包,它在内部使用 Rcpp
来创建类似散列的对象:
library(tidyverse)
library(hashmap)
dict = df2 %>%
mutate_if(is.factor, as.character) %>%
mutate(Value = X) %>%
gather(Label, Key, -Value) %>%
na.omit() %>%
{hashmap(.$Key, .$Value)}
这给你一个散列 table:
> dict
## (character) => (character)
## [e] => [d]
## [d] => [d]
## [f] => [d]
## [b] => [b]
## [a] => [a]
现在,要使用 df1$B
作为键提取值,只需执行以下操作:
dict[[df1$B]]
# [1] "a" NA "a" "d"
df1 %>%
mutate(Value = dict[[B]]) %>%
na.omit() %>%
select(-B)
结果:
A Value
1 1 a
3 3 a
4 4 d
数据:
df1 = read.table(text = "A B
1 a
2 c
3 a
4 e", header = TRUE, stringsAsFactors = TRUE)
df2 = read.table(text = "X Y Z
a NA NA
b NA NA
d e f", header = TRUE, stringsAsFactors = TRUE)
这是用于演示目的的通用版本,但此方法不如使用 hashmap
:
library(tidyverse)
df2 %>%
mutate(Value = X) %>%
gather(Label, Key, -Value) %>%
split(.$Label) %>%
map_dfr(~ cbind(A = na.omit(match(.$Key, df1$B)),
slice(., match(df1$B, .$Key)))) %>%
select(A, Value) %>%
arrange(A)
结果:
A Value
1 1 a
2 3 d
3 4 d
数据:
df1 = read.table(text = "A B
1 a
2 c
3 f
4 e", header = TRUE, stringsAsFactors = FALSE)
df2 = read.table(text = "X Y Z
a NA NA
b NA NA
d e f", header = TRUE, stringsAsFactors = FALSE)
注:
我首先复制了 df2$X
因为它在技术上也是一把钥匙。然后,我将 df2
重塑为长格式,并将 split
重塑为 Key
。对于每个键,我 sliced
与 df2$B
匹配的行,并将结果与 map_dfr
一起 rbind
。最后,只返回 Value
列。
请注意,我在此示例中使用了与 hashmap
示例中不同的 df1
,因为如果 df1$B
有重复项,此方法将不起作用。