如何在R中的数据框内比较和排序两个值?

时间:2016-06-24 17:21:25

标签: r sorting compare subset

这是我的第一篇文章,所以请放轻松我; D

对于我参与的一些研究,我们为脊髓切片产生了两个面积测量值。较小的测量是指由损伤形成的腔,较大的区域是整个脊髓。这些测量是在Photoshop中进行的,并使用相同的文档名称导出,但值明显不同。 例如,

$`T7-B9_TileScan_005_Merging001_ch00.tif`
              Label                               Document         Area
1827 Measurement 39 T7-B9_TileScan_005_Merging001_ch00.tif    92,041.52
1831 Measurement 40 T7-B9_TileScan_005_Merging001_ch00.tif 3,952,865.00

这实际上是我使用R的子集函数创建的简化版本来删除数据。我必须这样做的原因是因为疤痕区域的范围与总脐带区域的范围重叠,这意味着它们不能通过简单的尺寸排除来过滤。

我的示例数据集可以找到here。 为了生成这个,请在​​此处关注我的[EDITED]工作。

Scar.Ablation.Data <- read.csv("/Scar Ablation Data.csv", stringsAsFactors=F)

添加stringsAsFactors = F更正了稍后生成的错误。

test1 <- subset(Scar.Ablation.Data, Count != "", select = c(Label,Document,Area))

删除所有没有Count值的数据。当Photoshop导出数据时,它通过冗余测量完成。但是,所有这些冗余测量都不包含Count值,因此可以使用它们将其删除。建议的替代方法不起作用,因为R在Count列中没有读取NA值。

fileList = split(test1,test1$Document)

生成一个列表,其中测量值按文档名称分隔。

spineAreas = lapply(fileList, function(x) x[which(x$Area==max(x$Area)), ])

获取每个列表(表示给定文件名的所有数据),然后查找并返回每个文件的面积最大的行中的数据。

scarAreas = lapply(fileList, function(x) x[which(x$Area==min(x$Area)), ])

对于每个文件,我们希望所有行的数据的面积小于最大面积。 Lapply返回一个列表,所以我们现在想把它们变回dataFrames

spineData = do.call(rbind,spineAreas)
scarData = do.call(rbind,scarAreas)
row.names(spineData)=NULL #clean up row names
row.names(scarData)=NULL
write.csv(scarData, "/scarData.csv")
write.csv(spineData, "/spineData.csv")

在比较我的导出时,出现了以下问题:

  1. spineData包含Null值,但scarData没有。
  2. 通过在x$Area<max的函数中将x$Area==min切换为scarArea来解决此问题。输出虽然仍然不正确,但并没有因此修改而改变。

    1. 区域之间的比较并不总是有效。例如,对于样本“C1-B3_TileScan_002_Merging001_ch00.tif”,疤痕报告的面积高于脐带。
    2. 我尝试使用aggregate()函数尝试不同的比较方法,但这返回的数据与上述方法生成的数据完全相同。然而,R正在计算这些比较,它认为它正在做出正确的决定。这可能表示我的数字区域值存在某种格式或导入问题。

      spineAreas2 = aggregate(Area ~ Document, data = test1, max)
      scarAreas2 = aggregate(Area ~ Document, data = test1, min)
      
      spineData2 = do.call(rbind,spineAreas2)
      scarData2 = do.call(rbind,scarAreas2)
      
      row.names(spineData2)=NULL #clean up row names
      row.names(scarData2)=NULL #clean up row names
      
      do.call(rbind, lapply(spineAreas, data.frame, stringsAsFactors=FALSE))
      do.call(rbind, lapply(scarAreas, data.frame, stringsAsFactors=FALSE))
      #Then clean up row names as in first example, or pass row.names=F 
      #when writing to a .csv file
      
      write.csv(scarData2, "C/scarData2.csv")
      write.csv(spineData2, "CspineData2.csv")
      

      我可以将Null换成0或NA,我可以尝试这样做以解决这个问题。感谢@Cole对此问题的持续帮助,非常感谢。

2 个答案:

答案 0 :(得分:0)

好的,所以如果我理解正确的话,你想a)清理数据(你已经完成了)然后b)按文件名划分数据(也已经完成)然后最后c)比较每个区域内的区域测量值文件类型,较小的是疤痕,最大的是脊柱。您希望将每个列表分类为单个列表,一个用于疤痕数据,另一个用于脊柱数据(问题)。

为此,我们将使用lapply函数。它接受矩阵,数组或数据帧的每个元素并向其应用函数。在这里,我们编写自己的函数。它接受每个列表(表示给定文件名的所有数据),然后查找并返回每个文件的面积最大的行中的数据。

spineAreas = lapply(fileList, function(x) x[which(x$Area==max(x$Area)), ])

接下来我们做同样的事情,但这次我们想要更小的区域用于伤疤。因此,对于每个文件,我们希望来自面积小于最大面积的所有行的数据。 这种方法假设每个文件的最大区域是脊髓横断面,所有其他区域代表疤痕。

scarAreas = lapply(fileList, function(x) x[which(x$Area<max(x$Area)), ])

Lapply返回一个列表,所以现在我们要将它们转回dataFrames

spineData = do.call(rbind,spineAreas)
scarData = do.call(rbind,scarAreas)
#clean up row names
row.names(spineData)=NULL
row.names(scarData)=NULL

上述方法会将每个字符串转换为dataFrame中的一个因子。如果您不希望它们成为因素(偶尔会导致问题,因为它们对某些功能不起作用),那么您可以执行以下操作。

do.call(rbind, lapply(spineAreas, data.frame, stringsAsFactors=FALSE))
do.call(rbind, lapply(scarAreas, data.frame, stringsAsFactors=FALSE))
#Then clean up row names as in first example, or pass row.names=F 
#when writing to a .csv file

请告诉我这是你想要完成的事情。

答案 1 :(得分:0)

问题摘要

现在我有一个示例数据集,我可以看到一些问题。

第一个问题是你有一个.csv文件。 csv代表逗号分隔值,如您所见,您的文件不包含值之间的逗号。看起来它是tsv标签分隔值文件。在R中,您希望使用read.delim()函数阅读此内容,如下所示:

ablationData = read.delim("Scar Ablation Data.txt",stringsAsFactors=F)

(如果确实以制表符分隔,您可能还需要考虑使用.tsv扩展名对数据进行命名。

在阅读数据后很明显

  1. 对于&#39;糟糕&#39;读取,该文件包含&#34; Null&#34;这与R中的NULL对象不同(请注意所有上限)。使用x=="Null"是测试这些的正确方法(正如您之前所做的那样)。
  2. 没有Count数据的读取由""值表示。我猜测这与.tsv文件中没有值表示为""的性质有关,因为标签之间没有任何内容。请注意,如果您使用其他文件格式的位置,例如.csv ""将被视为NA这取决于如何R read.xxx函数处理不同的文件类型,对于将来要记住是一件好事。
  3. Count列代表&#39;功能的数量&#39;每次测量。似乎每个measurement都有一个measurement #行,该行是该度量的汇总摘要。然后,feature的每个measurement都有自己的行measurement #-Feature #。根据您对问题的描述,您希望删除个人&#39;功能&#39;测量并仅比较每个测量集的聚合值 。我不确定这是否是您实际打算/想要做的事情,因此我会仔细考虑您为什么要删除单个feature行,因为它们当然不是重复/冗余值正如你所说的那样。
  4. 如上所述,我们在许多列中都包含"""Null"值,否则这些值包含数字输入。这会导致这些列中的所有值转换为character类型,而不是numeric。这就是为什么以前的排序不起作用的原因,因为max()characters上与numerics的工作方式不同,非常。删除有问题的"" and "Null"值后,我们必须将所需的列投射到numeric数据类型。
  5. 数据的另一个问题是它的数字中包含,.。 R不喜欢,的数字,也不知道如何解释它们。因此,我们需要删除它们
  6. 摘要:

    • 读入数据(.tsv
    • 分离出所有"Null"值(请参阅下面的注释)
    • 删除所有单独的feature测量值,仅保留每个measurement集的聚合数据。
    • 从数字中删除所有,
    • 仅包含编号为numeric
    • 的列
    • 按文件名分隔数据
    • 处理每个文件
      • 查找最大measurement的汇总Area。这代表脊柱
      • 所有其他measurement值代表疤痕。
      • 将结果分成两个不同的数据集。一个用于疤痕,一个用于脊柱。
    • 添加&#34; Null&#34;价值回来(见下面的注释)

    问题:您确定要基于文件进行分离,然后仅比较聚合测量结果,还是真的要根据测量值进行分离然后进行比较该测量中的每个功能

    关于先前答案的说明

    spineData应该是唯一包含"Null"值的列表。这是因为完全由max()组成的数据集的min()"Null"只是"Null"。因此== max(data)对于每个"Null"数据点都是正确的(即"Null"=="Null")但< max(data)对于每个"Null"数据点都是假的(即{{1} }})。我真的不认为你想要使用"Null"< "Null",因为那时你将丢弃所有中间值(可能是有效的疤痕测量值),因为你有非 - &#34; Null&#34;数据

    如果你真的想要保留数据集中的==min(data)读数,我建议将它们拉出来,处理剩下的数据,然后在最后添加它们。

    解决方案

    读入数据。

    "Null"

    分开 data = read.delim("Scar Ablation Data.tsv",stringsAsFactors=F) 次测量

    "Null"

    删除所有data2 = data[-which(data$Area=="Null"),] 次测量,仅保留每个feature的汇总数据。仅保留measurementLabelDocument列。

    Area

    对于包含数字数据的所需列,请从数字中删除data2 = data2[-which(data2$Count==""),c("Label","Document","Area")] 并转换为,类型。

    numeric

    按文件/ data2$Area = as.numeric(gsub(",","",data2$Area)) 名称分隔数据。

    Document

    处理每个文件。最大fileList = split(data2,data2$Document) 值表示脊柱,所有其他(较小)值表示疤痕。这些语句中的每一个都返回一个包含我们所需结果的列表。

    Area

    转换回spineAreas = lapply(fileList, function(x) x[which(x$Area==max(x$Area)), ]) scarAreas = lapply(fileList, function(x) x[which(x$Area<max(x$Area)), ]) 。在这里,我添加了一个额外的步骤,以避免我们的数据转换为因子。

    dataFrame

    添加spineAreas = do.call(rbind, lapply(spineAreas, data.frame, stringsAsFactors=FALSE)) scarAreas = do.call(rbind, lapply(scarAreas, data.frame, stringsAsFactors=FALSE)) 的文件会重新读入并清理行名称。 仅在完成分析数据时执行此操作

    "Null"

    注意

    通过重新添加nullDocs = match(unique(data$Document[data$Label=="Null"]),data$Document) nullDocs = data.frame(data[nullDocs,c("Label","Document","Area")],stringsAsFactors=F) scarAreas = rbind(nullDocs,scarAreas) spineAreas = rbind(nullDocs,spineAreas) row.names(scarAreas)=NULL row.names(spineAreas)=NULL 值,我们的"Null"列将被强制返回Area类型,因为列中的每个元素必须具有相同的数据类型。这很重要,因为这意味着您无法在R上对数据执行任何有意义的操作。

    例如:character将返回

    spineAreas$Area>scarAreas$Area

    这可能会让我们相信我们没有正确排序数据。

    但是:[1] FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE TRUE TRUE FALSE FALSE TRUE FALSE FALSE TRUE TRUE [23] TRUE TRUE TRUE FALSE TRUE TRUE TRUE FALSE FALSE TRUE FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE TRUE TRUE 将返回

    as.numeric(spineAreas$Area)>as.numeric(scarAreas$Area)

    这表示前3个值的字符串(在本例中为[1] NA NA NA TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE [28] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE )由"Null"替换,然后表示我们的数据已正确排序。

    因此,当您完成数据分析时,请将NA值添加回来,或者将您想要的列重新编号为数字(例如"Null"

    如果你想避免这种混乱的打字业务(首选)

    读入您的数据,以便所有spineAreas$Area = as.numeric(spineAreas$Area)"""Null"表示。这会让生活变得更轻松,但不会让您免于移除NA并将数据转换为数字。

    以下是您需要更改的行

    ,

    即使在添加了空读数之后,这也会使您的数据保持为data = read.delim("Scar Ablation Data.tsv",na.strings=c("NA","Null",""),stringsAsFactors=F) data2 = data[-which(is.na(data$Area)),] data2 = data2[-which(is.na(data2$Count)),c("Label","Document","Area")] nullDocs = match(unique(data$Document[is.na(data$Label)]),data$Document) ,并且可能是首选方法。