【问题标题】:Unwrapping continuous data into a single row in R在 R 中将连续数据展开为单行
【发布时间】:2013-08-08 17:19:06
【问题描述】:

我有一个软件可以生成宽度有限的实验数据,这样一串数据点将被包装成一系列行,在最终的 csv 中限制为 4 列宽,而不是每个变量一行(下面的 A 和 B)这是我需要的形式。(下面的示例 csv)

A,1,3,3,2
,5,6,7,8
,9,10,11,12
,13,1,15,6
,17,1,2,20
B,1,2,3,7
,7,6,7,8
,9,10,11,12
,13,15,15,16
,17,18,3,2

在实际数据中,这让我每天要处理大约 53,000 行,所以我想知道是否有一个函数可以让我对给定的数据子集(每个变量)展开或重新维度化成单行。在上面的示例中,变量 A 后面的数字将组合成一行,同时保持顺序(即 1,3,3,2,5...),B 也是如此,依此类推。

根据请求,dput 输出生成上述简化示例..

 structure(list(V1 = structure(c(2L, 1L, 1L, 1L, 1L, 3L), .Label = c("", 
 "A", "B"), class = "factor"), V2 = c(1L, 5L, 9L, 13L, 17L, 1L
 ), V3 = c(2L, 6L, 10L, 14L, 18L, 2L), V4 = c(3L, 7L, 11L, 15L, 
 19L, 3L), V5 = c(4L, 8L, 12L, 16L, 20L, 4L)), .Names = c("V1", 
 "V2", "V3", "V4", "V5"), row.names = c(NA, 6L), class = "data.frame")

【问题讨论】:

  • 可以用read.csv 读入这个文件吗?如果可以,你能dput 它给你什么吗?如果它完全有效,我猜第 2-5 行的开头会有一个 NA 等。另外,在你的问题中也可以尝试readLinesdput(head(data)。第二种方法肯定会奏效。任何一个都需要编写一个小函数来恢复数据的完整性。听起来像现实世界!而且,实际数据行的开头是否总是大写字母?
  • 嗯,我对 R 真的很陌生,所以我不肯定我会跟随。我通常使用 read.csv 读取数据。通常,变量标题之间的所有行(准确地说总是大写的“A:, B:,..”)显示为空白。dput 依赖于另一个库,还是 read.csv 中的参数?
  • 如果您已将数据读入名为tst 的变量中,请执行dput(head(tst)) 并将结果复制到上面的问题中。这向我们展示了数据的结构,并提供了一小部分用于测试。

标签: r dataframe plyr


【解决方案1】:

您可以使用外部工具来预处理文件,

read.csv(pipe("sed -e :a -e '$!N;s/\\n,//;ta' -e 'P;D' file.txt"), head=FALSE)

本质上,file.txt 首先由 unix 工具 sed 处理,该工具执行搜索和替换并将新内容返回给 R。我改编自 this page 的正则表达式执行以下任务:

  If a line begins with a comma, append it to the previous line 
  and replace the "," with nothing

编辑(eddi -- 注意:这似乎不适用于 Mac OS) 以下是 sed 解析以下命令的方式:

read.csv(pipe("sed ':a; N; s/\\n,/,/; t a; P; D' file.txt"), head=FALSE)

:a       # label (named "a") we're going to come back to
N        # read in the next line into pattern space, together with the newline character
s/\n,/,/ # if there is a newline followed by comma, delete the newline
t a      # go back to "a" and repeat until the above match fails (t stands for test)
P        # print everything in pattern space up to and including last \n
D        # delete everything in pattern space up to and including last \n

【讨论】:

  • 我喜欢这些,但它们从不透明!
  • 如果更小的孩子read xkcd comics,也许他们会变得更自然;毕竟它与笑脸和短信语言并没有太大区别。 grep 人站了起来。
  • 恐怕你已经因为这个而失去了我。我不明白如何使用它或它在 read.csv 之外的任何含义:-/。
【解决方案2】:

grep、paste 和 read.table 在这里非常方便。

# read in your data raw
X <- read.table("file")

# Any line that does NOT start with a comma, add a line break, 
# then re-read with read.table
read.table(text=paste(ifelse(grepl("^,", X), X, paste("\n", X)), collapse=""), sep=",")

产量:

  V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 V16 V17 V18 V19 V20 V21  
1  A  1  3  3  2  5  6  7  8   9  10  11  12  13   1  15   6  17   1   2  20  
2  B  1  2  3  7  7  6  7  8   9  10  11  12  13  15  15  16  17  18   3   2

【讨论】:

  • 检查结果的顺序:要么你要么我解析错了。或者没关系,我看到 OP 的 dput 和问题中的数据之间存在差异。我用了一个,你用了另一个。
  • @BryanHanson,我使用了 OP 顶部的数据集,你是对的,看起来它们是不同的
  • 谢谢 Ricardo,我现在有很多选择可以尝试。
【解决方案3】:

这是另一种基本的 R 解决方案。它使用gsub(),并且简短易读(至少对我而言)。

txt = readLines("file.txt")

# Join into one long string with newlines.
txt_long = paste(txt, collapse="\n")

# Remove newlines directly preceding a comma.
newtxt = gsub("\\n,", ",", txt_long)

read.table(text=newtxt, sep=",")
#   V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 V16 V17 V18 V19 V20 V21
# 1  A  1  3  3  2  5  6  7  8   9  10  11  12  13   1  15   6  17   1   2  20
# 2  B  1  2  3  7  7  6  7  8   9  10  11  12  13  15  15  16  17  18   3   2

【讨论】:

  • 优秀:精简,但直截了当。我喜欢这个问题产生的答案范围。多聪明。相比之下,我的回答太野蛮了!我不知道 read.table 有一个 text 参数。
【解决方案4】:

这有点难看,但这是我想到的第一个通用策略:

library(zoo)
library(plyr)
dat$V1 <- na.locf(dat$V1)
> ddply(dat,.(V1),function(x) c(t(as.matrix(x[,-1]))))
  V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 V16 V17 V18 V19 V20
1  1  3  3  2  5  6  7  8  9  10  11  12  13   1  15   6  17   1   2  20
2  1  2  3  7  7  6  7  8  9  10  11  12  13  15  15  16  17  18   3   2

假设您将数据读入名为dat 的对象并使用na.strings = ""。您可以在之后添加AB 变量信息,或者可能将其填充到匿名ddply 函数中。

可能有办法直接使用dcast 重塑它,但我想不出办法。

【讨论】:

  • 好吧,这听起来很合理。每个变量的数组长度始终相同,未使用的位置显示为 0 填充。它们也总是按相同的顺序排列,所以如果我必须为行名重新附加变量标题,这应该不是问题。考虑到我对 R 和一般编程的了解程度,您能否为我解压缩一下语法。我正在跟进,直到 ddply 等。我之前尝试过使用 ddply 没有运气,因为我似乎无法找到对许多参数的直观、非程序员友好的解释。我特别记得不了解 function(x) 位。谢谢。
  • @user2510207 ddply 的第三个参数是应用于每个“块”的函数。您可以传递现有函数的名称,也可以定义一个新函数“内联”,可以这么说,就像我在这里所做的那样。这被称为“匿名函数”,因为它只存在于ddply 调用的上下文中。
  • 好的,很酷。那么你定义的函数 c(t(as.matrix(x[,-1) 以及它是如何完成任务的?
  • @user2510207 它只获取值并 (1) 从数据帧转换为矩阵,减去第一列,(2) 转置矩阵,以及 (3) 将值展平为单个向量。转置是必要的,因为 R 按列而不是按行存储矩阵。
  • 我写的函数本质上是 Joran 描述的手动版本。
【解决方案5】:

你不只是喜欢仪器制造商吗?

这是一种方法,我认为它不是很完美,因为我无法完全测试没有所有数据,但你可以。

编辑:更新功能

cleanData <- function(df) {
    good <- c() # holds indices of lines that start a row in the final data set
        # Find the 'starter' rows
    for (n in 1:nrow(df)) {
        if (df[n,1] != "") good <- c(good,n)
        }

    # Now go back and put it back together
    # Get one row in 1st to set dimensions

    newDat <- data.frame(mydat = df[(good[1]:(good[2])-1),])
    offset <- nrow(newDat)-1
    data <- as.numeric(t(as.matrix(newDat[,-1])))
    label <- df[1,1]
    newDat <- data.frame(data)
    names(newDat) <- label
    #print(newDat) # OK

    # now do them all
    for (n in 2:length(good)) {
        use <- good[n]:(good[n] + offset)
        data <- as.numeric(t(as.matrix(df[use,-1])))
        label <- df[good[n],1]
        newCol <- data.frame(data)
        names(newCol) <- label
        newDat <- cbind(newDat, newCol)
        }

    newDat
    }

将上面的函数复制并粘贴到R,然后执行newTst &lt;- cleanData(tst),其中tst 是来自read.csv 的数据框。如果可行,请查看newTst 或执行str(newTst)

根据你的测试数据它给出:

'data.frame':   20 obs. of  2 variables:
 $ A: num  1 2 3 4 5 6 7 8 9 10 ...
 $ B: num  1 2 3 4 NA NA NA NA NA NA ...

【讨论】:

  • 感谢 Bryan 的时间,这是需要编写的大量代码来提供帮助。我会试试这些方法。
  • 这是一个很好的拼图,而不是我应该做的工作!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-28
  • 2018-05-29
相关资源
最近更新 更多