使用另一列 R 中的值通过 str_split 处理数据框列

Processing dataframe column via str_split using values in another column R

我想知道是否有更好的方法来解决以下问题

我有一个具有以下示例结构的数据框:

Split_key label sub_label
A_B_C 7 ""
A_B_C 7 ""
A_B_C 8 ""
A_B_C 8 ""
A_B_C 10 ""
A_B_C 10 ""
D_E_F 2 ""
D_E_F 7 ""
D_E_F 15 ""
G_H_I 1 ""
G_H_I 2 ""
G_H_I 3 ""

我希望用一个值填充 sub_label,该值对应于在“_”字符上拆分 Split_key 中的值,并根据标签获取正确的元素。正确的元素是在 Split_key.

中共享相同值的唯一排序标签数组中标签中值的索引

此处显示了正确的最终结果。

Split_key label sub_label
A_B_C 7 A
A_B_C 7 A
A_B_C 8 B
A_B_C 8 B
A_B_C 10 C
A_B_C 10 C
D_E_F 2 D
D_E_F 7 E
D_E_F 15 F
G_H_I 1 G
G_H_I 2 H
G_H_I 3 I

这是我的初步尝试。

for (row_n in 1:nrow(df)){
  df%>%filter(`Split_key`==df[row_n,"Split_key"][[1]])->duplicates
  shift<-which(sort(unique(duplicates$label))==df[row_n,"label"][[1]])
  df[row_n,"sub_label"]<-str_split(df[row_n,"Split_key"],"_")[[1]][shift]
}

此解决方案有效,但比我希望的大型数据帧慢。有没有不使用 for 循环来完成这个任务的方法?

这将比循环更快:

library(dplyr)
dat %>%
  group_by(Split_key) %>%
  mutate(sub_label2 = strsplit(Split_key[1], "_")[[1]][ match(label, sort(unique(label))) ]) %>%
  ungroup()
# # A tibble: 12 x 4
#    Split_key label sub_label sub_label2
#    <chr>     <int> <chr>     <chr>     
#  1 A_B_C         7 A         A         
#  2 A_B_C         7 A         A         
#  3 A_B_C         8 B         B         
#  4 A_B_C         8 B         B         
#  5 A_B_C        10 C         C         
#  6 A_B_C        10 C         C         
#  7 D_E_F         2 D         D         
#  8 D_E_F         7 E         E         
#  9 D_E_F        15 F         F         
# 10 G_H_I         1 G         G         
# 11 G_H_I         2 H         H         
# 12 G_H_I         3 I         I         

如果 Split_key 中编码的元素少于 sub_label 中的不同值,那么这些行将得到 NA

演练:

  • group_by(Split_key):因为我们需要为每个Split_key跟踪唯一的label,所以我们在这个字段进行分组,一次简化为一组处理;
  • strsplit(Split_key[1], ")")[[1]]:在一个特定的组中,我们只需要拆分 Split_key 个值中的一个,而不是所有的值(因为它们都是相同的),这在内部产生了一个向量这样作为第一组中的 c("A", "B", "C")
  • match(label, sort(unique(label))) 将(第一组)翻译成 match(c(7,7,8,8,10,10), c(7,8,10)),然后翻译成 c(1,1,2,2,3,3);这用于索引上一个项目符号
  • 的向量 c("A","B","C")

这是实现目标的另一种方法: 逻辑:

  1. 分组 Split_key
  2. 使用 data.table
  3. 中的 rleid 函数为 label 创建分组变量
  4. 使用一些 stringr 函数来达到目标​​:
library(dplyr)
library(stringr)
library(data.table)
df %>% 
  group_by(Split_key) %>% 
  mutate(group = rleid(label)) %>%
  mutate(sub_label= str_sub(str_replace_all(Split_key, "[^[:alnum:]]", ""), group, group), .keep="unused")
 Split_key label sub_label
   <chr>     <int> <chr>    
 1 A_B_C         7 A        
 2 A_B_C         7 A        
 3 A_B_C         8 B        
 4 A_B_C         8 B        
 5 A_B_C        10 C        
 6 A_B_C        10 C        
 7 D_E_F         2 D        
 8 D_E_F         7 E        
 9 D_E_F        15 F        
10 G_H_I         1 G        
11 G_H_I         2 H        
12 G_H_I         3 I  

我们可以使用 factor 路由,即在按 'Split_key' 分组后,scan 'Split_key' 的 first 元素并使用 integerfactor 列 'label' 转换为索引

library(dplyr)
df %>%
    group_by(Split_key) %>% 
    mutate(sub_label = scan(text = first(Split_key), what = "", 
      sep="_", quiet = TRUE)[as.integer(factor(label))]) %>%
    ungroup

-输出

# A tibble: 12 × 3
   Split_key label sub_label
   <chr>     <int> <chr>    
 1 A_B_C         7 A        
 2 A_B_C         7 A        
 3 A_B_C         8 B        
 4 A_B_C         8 B        
 5 A_B_C        10 C        
 6 A_B_C        10 C        
 7 D_E_F         2 D        
 8 D_E_F         7 E        
 9 D_E_F        15 F        
10 G_H_I         1 G        
11 G_H_I         2 H        
12 G_H_I         3 I    

数据

df <- structure(list(Split_key = c("A_B_C", "A_B_C", "A_B_C", "A_B_C", 
"A_B_C", "A_B_C", "D_E_F", "D_E_F", "D_E_F", "G_H_I", "G_H_I", 
"G_H_I"), label = c(7L, 7L, 8L, 8L, 10L, 10L, 2L, 7L, 15L, 1L, 
2L, 3L), sub_label = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
NA, NA)), class = "data.frame", row.names = c(NA, -12L))