【问题标题】:using for loop for data cleaning使用 for 循环进行数据清理
【发布时间】:2019-08-31 19:38:05
【问题描述】:

我正在重组包含血压读数的变量。每个读数包含由正斜杠 (/) 分隔的收缩压和舒张压值。对于此示例,每行(即每人)有三个读数。

我想要的输出是每个读数的收缩压和舒张压值都有单独的变量。

以下是 csv 格式的数据示例:

id,v1,v2,v3  
1,116 / 77,121 / 68,105 / 76  
2,164 / 67,171 / 79,155 / 68  
3,146 / 109,,  
4,120 / 80,102 / 64,137 / 87   
5,112 / 50,130 / 40,  

加载 tidyverse 后,我可以对每个读数使用单独的方法来执行此操作,例如,

blPr <- read_csv('BlPr.csv')  
blPr <- blPr %>% separate (v1 , c('v1_sys' , 'v1_dias') , sep = '/' , remove = FALSE) 

但是,由于实际数据集每人有多个读数,因此我试图通过使用 for 循环来消除多行。在查看了网络上的一些示例后,我尝试了:

for (i in 1:3) {  
  blPr <- blPr %>% separate (v[i] , c('v[i]_sys' , 'v[i]_dias') , sep = '/' ,   remove = FALSE)  
}  

返回错误信息:

Error in eval_tidy(enquo(var), var_env) : object 'v' not found

我已经以多种方式修改了代码,但由于我不明白哪里出了问题,所以我一无所获。

【问题讨论】:

  • 嗨@David,您的示例的预期输出是什么?
  • 奇怪:表头元素用,分隔,数据部分用/分隔
  • 我想为收缩压和舒张压读数设置单独的变量,现在在单个变量中用斜线分隔。所有变量在 csv 文件中用逗号分隔。
  • 嗨@David,欢迎来到 StackOverflow!您可以使用dput(head(df))(其中df 是您的数据框的名称)并使用问题左下角的edit 选项将其添加到您的问题中吗?如果您能做到这一点并添加您的预期输出,这将有助于获得更快和相关的答案。
  • 您希望每个 ID 保留哪些读数?第一个,最后一个,全部?

标签: r


【解决方案1】:

我看到有人的答案刚刚被接受,但无论如何我都会发布我的。如果要以尽可能少的方式更改您的代码,可以采用以下方法:

for (i in 1:3) {
  blPr <- blPr %>% 
    separate(paste0('v', i), c(paste0('v', i, '_sys'), paste0('v', i, '_dias')), sep = ' / ', remove = F)
}

简短的解释(希望)帮助您理解为什么您的代码不起作用: 您可以使用不带引号的变量(即列)名称作为 tidyverse 参数,但这些不是引用透明的。这意味着您的代码在blPr 内寻找名为v 的列字面意思,但显然没有找到。有时,尽管据我所知并非总是如此,tidyverse 动词(例如separate)接受带有列名的字符串来表示这些列——我在上面的代码中使用的特性(注意'v' 是一个字符串)。如需更多信息,您可以阅读 tidy evaluation、quasi-quotation 等。

【讨论】:

  • 这段代码对我来说更清晰,也感谢您的解释——对我来说很有意义。对于可能会咨询此问题的其他人,我已将其投票为正确答案。对于任何尴尬,我深表歉意——我是 StackOverflow 的新手。
【解决方案2】:

下面的代码有效...

# Create dataframe
blPr = read.table(text = '
id,v1,v2,v3  
1,116 / 77,121 / 68,105 / 76  
2,164 / 67,171 / 79,155 / 68  
3,146 / 109,,
4,120 / 80,102 / 64,137 / 87   
5,112 / 50,130 / 40,
', header = T, sep = ",")

library(tidyr)

for (i in c(1:3)){
eval(parse(text=paste0(  
"blPr <- blPr %>% separate (v",i," , c('v",i,"_sys' , 'v",i,"_dias') , sep = '/' , remove = FALSE)"
)))
}

【讨论】:

  • 谢谢,代码运行良好,得到了我想要的结果。我将做一些工作来分解代码并更好地理解它。有这个例子会有所帮助。
  • 太好了,我很高兴它成功了。你能把它标记为“正确”吗?
【解决方案3】:

您可以做的是保留所有读数并将数据整理成一个整洁的格式:

result <- data %>%
    gather("reading", "value", -id) %>%
    mutate(value = trimws(value),
           value = ifelse(value == "", NA_character_, value)) %>%
    arrange(id, reading) %>%
    separate(value, c("systolic", "diastolic"), "/", convert = TRUE)


> head(result)
   id reading systolic diastolic
1   1      v1      116        77
2   1      v2      121        68
3   1      v3      105        76
4   2      v1      164        67
5   2      v2      171        79
6   2      v3      155        68

你可以更进一步,a) 删除 NA,b) 把它变成长格式:

result_long <- result %>%
    filter(complete.cases(.)) %>%
    gather("reading_type", "value", -id, -reading) %>% 


> head(result_long)
   id reading reading_type value
1   1      v1     systolic   116
2   1      v2     systolic   121
3   1      v3     systolic   105
4   2      v1     systolic   164
5   2      v2     systolic   171
6   2      v3     systolic   155

整洁的格式让整理和绘制数据变得非常容易。将它们恢复为人类可读的形式也很容易。 result 中选择的格式可能是人类可读和易于处理之间的一个很好的折衷。

绘图

library(ggplot)

ggplot(result_long) + 
    geom_point(aes(reading, value, color = reading_type, group = reading_type)) +
    geom_line(aes(reading, value, color = reading_type, group = reading_type)) +
    facet_wrap(id ~ .)

将数据放入宽格式

result_wide <- result_long %>% 
    spread("reading_type", "value", drop = TRUE) %>%
    unite("value", c("systolic", "diastolic"), sep = " / ") %>%
    spread("reading", "value")


> result_wide
  id        v1       v2       v3
1  1  116 / 77 121 / 68 105 / 76
2  2  164 / 67 171 / 79 155 / 68
3  3 146 / 109     <NA>     <NA>
4  4  120 / 80 102 / 64 137 / 87
5  5  112 / 50 130 / 40     <NA>

数据

library(tidyverse)

data <- read.table(text = '
id,v1,v2,v3  
1,116 / 77,121 / 68,105 / 76  
2,164 / 67,171 / 79,155 / 68  
3,146 / 109,,
4,120 / 80,102 / 64,137 / 87   
5,112 / 50,130 / 40,
', header = T, sep = ",")

【讨论】:

  • 我知道你要去哪里,但我认为这在这里没有意义。在原始数据框中,每一行都是一个个体,在不同时间有几个读数(未显示)。可以直接查看这些读数的进展情况,或者如果它们位于单独的列中,它们是否符合某些医学标准。个人是分析的单位,将他们的所有读数放在同一行中是最有意义的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-17
  • 2018-05-14
  • 1970-01-01
  • 2022-01-12
  • 2018-08-31
  • 1970-01-01
相关资源
最近更新 更多