【问题标题】:Subset base function ignoring repeated entries when outputting输出时忽略重复条目的子集基函数
【发布时间】:2021-10-16 06:25:05
【问题描述】:

我最近询问如何使用字典文件来重新编码数据集中的值 (Working with data values (dictionary). dataframes and recoding in R)

我遇到了一个更简单的问题,但该修复不起作用。假设我有以下数据集,每一行都是一个地理单位,V1 列列出了地理包找到的“第一个邻居”,但使用行号列出它

V1 <- c(1, 2, 1)
id <- c(110001, 110002, 110003)
dataset <- as.data.frame(matrix(c(id, V1), ncol=2))
colnames(dataset) <- c("id", "V1")

所以在这个数据集上,区域 110001 是它自己的邻居 (V1 = 1),区域 110003 是 110001 (V1 = 1) 的邻居。 现在,我不想将 V1(第一个邻居)显示为 "1, 2, 1",而是将其显示为地理区域的 id"110001, 110002, 110001"

所以,我创建了一个“字典”文件,其中包含地理区域的行号和 id:

dictionary <- as.data.frame(matrix(c(dataset$id, 1:nrow(dataset)),ncol=2))
colnames(dictionary) <- c("id","row")

然后,我尝试使用 mutate 映射这些。请注意,我有许多邻域变量(V1-V30),而我在示例中只使用了一个,所以我将使用转换为所有的语法:

new_dataset <- dataset %>% mutate(across(starts_with("V"), ~subset(dictionary, row == cur_column(), select= id)))     

这应该做的是:跨列运行,将值与字典行中的值进行比较,然后返回适当的 id。似乎问题在于dataset$V1 中的重复条目(在此示例中,第 1 行和第 3 行等于“1”)。如果我逐行进行,这将起作用:

first_row <- dataset[1,] %>% mutate(V1 = subset(dictionary, row == V1, select= id))    
second_row <- dataset[2,] %>% mutate(V1 = subset(dictionary, row == V1, select= id))  
third_row <- dataset[3,] %>% mutate(V1 = subset(dictionary, row == V1, select= id))

我的印象是“子集”忽略了重复的条目。例如,如果我运行这个:

 subset(dictionary, row == dataset$V1, select= id)

它应该返回"110001, 110002, 110001",但只返回"110001, 110002"

关于如何让子集返回所有内容或其他方法的任何想法?

【问题讨论】:

  • 只是一个提示:data.frame(id, V1) 是一种更方便的方式来定义该 data.frame。你不需要那种matrix() + colnames() 方式。
  • 为什么V1 == 1110001 取代而不是110003
  • 谢谢马丁!所以,V1 == 1 映射到字典中的row == 1 值,等于110001
  • @akrun 抱歉,我误点击了解决方案按钮,而不是点赞按钮。我刚刚开始测试解决方案,然后才接受它们。
  • 是的,我觉得很有趣,但不能太确定在线

标签: r dataframe subset matching


【解决方案1】:

我们可以使用rowwise

library(dplyr)
dataset %>%
     rowwise %>% 
     mutate(V1 = subset(dictionary, row == V1, select= id)$id) %>%
     ungroup

-输出

# A tibble: 3 x 2
      id     V1
   <dbl>  <dbl>
1 110001 110001
2 110002 110002
3 110003 110001

data.table

library(data.table)
 setDT(dataset)[dictionary, V1 := i.id, on = .(V1 = row)]
> dataset
       id     V1
1: 110001 110001
2: 110002 110002
3: 110003 110001

如果有多个列,例如“V1”、“V2”等

dataset$V2 <- V1[c(1, 3, 2)]
nm1 <- paste0("V", 1:2)
setDT(dataset)
for(nm in nm1) 
   dataset[dictionary, (nm) := i.id, on = setNames("row", nm)][]

-输出

> dataset
       id     V1     V2
1: 110001 110001 110001
2: 110002 110002 110001
3: 110003 110001 110002

【讨论】:

  • data.table 的解决方案很简单但很棒。
  • 第一个解决方案在有很多 V 的数据集中没有通过。对于第二个,使其适用于更多 V 需要申请,但似乎工作正常。不过,我不想要一个名为“newid”的新列,所以我将其更改为:setDT(neighbors_dataset)[dictionary, V1 := i.id, on = .(V1 = row)]。谢谢!
  • @jpugliese 抱歉,我认为最好使用新列进行更新
  • apply(neighbors_dataset, 2, function(x) {setDT(neighbors_dataset)[dictionary, x := i.id, on = .(x = row)]}) 错误:argument specifying columns specify non existing column(s): cols[1]='x' 我认为 apply 理解这个语法;如何在 setDT 中传递参数?
  • @jpugliese 你的意思是多列
【解决方案2】:

您可以对修改后的数据集使用自左连接:

library(dplyr)

dataset %>% 
  left_join(
    dataset %>% 
      group_by(V1) %>% 
      slice(1),
    by = "V1") %>% 
  select(-V1)

返回

    id.x   id.y
1 110001 110001
2 110002 110002
3 110003 110001

【讨论】:

    【解决方案3】:

    也许像下面这样的基本 R 选项?

    transform(
      dataset,
      V1 = ave(id, V1, FUN = function(x) head(x, 1))
    )
    

    给了

          id     V1
    1 110001 110001
    2 110002 110002
    3 110003 110001
    

    【讨论】:

      猜你喜欢
      • 2013-01-22
      • 1970-01-01
      • 2016-04-16
      • 1970-01-01
      • 1970-01-01
      • 2013-03-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多