【问题标题】:awk separate rows if "$2 are the same and max and min value <= 1" and "$2 are the same and max and min value < 1"如果“$2 相同且最大值和最小值 <= 1”和“$2 相同且最大值和最小值 < 1”,则 awk 分隔行
【发布时间】:2014-07-14 23:06:53
【问题描述】:

如果我们有一个输入文件:input.csv

cpdID,cpd_number,Cell_assay_id,Cell_alt_assay_id,Cell_type_desc,Cell_Operator,Cell_result_value,Cell_unit_value,assay_id,alt_assay_id,type_desc,operator,result_value,unit_value,Ratio_operator,Ratio,log_ratio,Cell_experiment_date,experiment_date,Cell_discipline,discipline
49,cpd-7788990,1212,2323, IC50 ,,100,uM,1334,1331,Ki,,10,uM,,10,-1,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-7788990,5555,6666, IC50 ,>,150,uM,1334,1331,Ki,,10,uM,>,15,-2,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-7788990,8888,9999, IC50 ,,200,uM,1334,1331,Ki,,10,uM,,20,-3,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-6666666,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-1111,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-1111,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1.1,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-1111,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1.2,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-1111,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1.3,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme

我们想将此 input.csv 分成 2 个文件,以便我们可以执行以下步骤:“如果 $2 与 $17

"如果$2相同且$17中max减min

  • 注意:如果 $2 本身是唯一的,我们希望将其保留在这里(以 cpd-6666666 为例)

  • 注意:cpd-1111 ($17 max-min) = -1-(-1.3)=0.3

输出文件1.csv

cpdID,cpd_number,Cell_assay_id,Cell_alt_assay_id,Cell_type_desc,Cell_Operator,Cell_result_value,Cell_unit_value,assay_id,alt_assay_id,type_desc,operator,result_value,unit_value,Ratio_operator,Ratio,log_ratio,Cell_experiment_date,experiment_date,Cell_discipline,discipline
49,cpd-6666666,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-1111,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-1111,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1.1,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-1111,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1.2,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-1111,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1.3,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme

“如果$2相同且$17中max减min>1”,则放入另一个文件中

outfile2.csv(其中 $17 中的最大值和最小值=-1-(-3)=2 > 1)

cpdID,cpd_number,Cell_assay_id,Cell_alt_assay_id,Cell_type_desc,Cell_Operator,Cell_result_value,Cell_unit_value,assay_id,alt_assay_id,type_desc,operator,result_value,unit_value,Ratio_operator,Ratio,log_ratio,Cell_experiment_date,experiment_date,Cell_discipline,discipline
49,cpd-7788990,1212,2323, IC50 ,,100,uM,1334,1331,Ki,,10,uM,,10,-1,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-7788990,5555,6666, IC50 ,>,150,uM,1334,1331,Ki,,10,uM,>,15,-2,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-7788990,8888,9999, IC50 ,,200,uM,1334,1331,Ki,,10,uM,,20,-3,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme

这是尝试从以下链接修改

awk/bash remove lines with an unique id and keep the lines that has the max/min value in a column under the same ID

#!/usr/bin/awk -f

BEGIN { FS="," }

NR==1 {print; next}

{
  a[$2,$17]=$0

  h=high[$2]
  high[$2]=$17>h || h=="" ? $17 : h

  m=mid[$2]
  mid[$2]=l<$17<h || m=="" ? $17 : m

  l=low[$2]
  low[$2]=$17<l || l=="" ? $17 : l
}

END {
  for(i in high) {
    if(high[i]-low[i]<=1) {
      print a[i,high[i]]
      print a[[i,mid[i]]
      print a[i,low[i]]
    }
  }
}

输出:

cpdID,cpd_number,Cell_assay_id,Cell_alt_assay_id,Cell_type_desc,Cell_Operator,Cell_result_value,Cell_unit_value,assay_id,alt_assay_id,type_desc,operator,result_value,unit_value,Ratio_operator,Ratio,log_ratio,Cell_experiment_date,experiment_date,Cell_discipline,discipline
49,cpd-1111,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-1111,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-1111,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1.3,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-6666666,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-6666666,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme
49,cpd-6666666,8888,9999, IC50 ,,400,uM,1334,1331,Ki,,10,uM,,40,-1,12/6/2006 0:00,2/16/2007 0:00,Cell,Enzyme

由于未知原因,此脚本无法正确打印出中间范围值。我可以知道是否有任何大师有 cmets/解决方案吗?

【问题讨论】:

  • 我很惊讶,甚至运行。我不认为 a &lt; b &lt; c 是一个有效的 awk 声明。将该比较分成两部分,看看它是否有效。
  • a
  • 您似乎正在尝试使用mid 数组来捕获所有不是最小/最大的行并且这不起作用,因为mid 将只包含一行。此外,a 只会捕获每个 $2,$17 的唯一组合。如果文件按$2(看起来是这样)分组,您可以在$2 更改文件时使用更直接的测试技术来决定如何操作数据。
  • 我明白了。所以即使我们给中间数组一个范围,也没有办法在awk中获取多行?
  • “如果文件按 $2 分组(看起来是这样),您可以使用更直接的测试技术来测试文件中 $2 更改时决定如何操作数据。”您能否提供一些“当 2 美元更改时的直接测试技术”的示例?谢谢。

标签: bash csv awk


【解决方案1】:

看看这个,这是一个在每个组的 id 更改时处理它的示例:

#!/usr/bin/awk -f

BEGIN {FS=","; f1="a"; f2="b"}

FNR==1 { print $0 > f1; print $0 > f2; next }

$2!=last_id && FNR > 2 { handleBlock() }

{ a[++cnt]=$0; m[cnt]=$17; last_id=$2 }

END { handleBlock() }

function handleBlock() {
  if( m[1]-m[cnt]<=1 ) fname = f1
  else fname = f2
  for( i=1;i<=cnt;i++ ) { print a[i] > fname }
  cnt=0
}

这是一个可执行的 awk 文件。当将其放入名为 awkochmod +x awko 的文件中时,它可以像 awko data 一样运行,用于名为“data”的输入文件。

我为另一个问题编写的脚本基于我假设文件元素的输入顺序是未知的 - 其中$2 字段可以按任何顺序排列,并且只有最小值和最大值很重要。在这个问题中,OP 希望根据最小/最大值将与 $2 字段相关的所有行发送到一个文件或另一个文件。

此问题的输入文件具有此脚本所依赖的以下属性:

  • 标题在第一行
  • $2 字段已分组
  • 最大值是组的第一个元素
  • 最小值是组的最后一个值

如果有一个按资源 id 排序的资源列表,一种用于最低限度加载数据的常用算法是仅在资源 id 更改时才加载它。在这里处理分组条目也可以这样做。举个例子:

a
a
a
b <- this is a good place to process all the prior "a" entries
b
c <- process "b" entries here
c
EOF <- the end of the file.  process the last group ( the "c" entries here )

考虑到这一点,下面是脚本的分解:

  • BEGIN 块中设置FS 和一些输出文件名(“a”和“b”用于我的测试)
  • 第一行是标题 - 将它放在每个文件中,f1f2
  • 如果是$2 != last_id,则调用handleBlock()函数进行处理。
  • 将整行存储在数组a$17 中数组m 中并设置last_id=$2(数组名称很糟糕)。
  • cnt 变量表示每个组中有多少条目(我称之为块)
  • handleBlock() 只会在 $2 id 更改或在文件末尾捕获 END 块中的最后一个组时调用。
  • handleBlock() tests the OP's condition usingm( max ism[1]and min is m[cnt] ) to determine the output file name and then prints all elements froma` 到所选文件名。

【讨论】:

  • 感谢您的评论!但是,当“awk -f average2.awk input.csv”时,似乎没有生成任何内容。猜猜我们可能需要等待您的详细解释才能完全理解此脚本并因此对其进行修改。
  • 你为什么打电话给handleBlock()END?那不是总是打印最后一行吗?
  • @ssdecontrol - 在完整查看之前不会打印任何组。 handleBlock() 用于捕获仅在到达文件末尾时才知道其结尾的最后一组。当END 块被注释掉时,只有cpd-6666666 数据行被写入a
  • 这确实是一种优雅的方法。只是要仔细检查一下:handleBlock() 不是 awk 内置函数,对吧? Google 搜索没有任何提示。
  • @Chubaka - 该函数在文件末尾的function handleBlock() { ... } 代码中本地定义。函数是放置多次调用代码的好地方。这是user defined functions 的 GNU Awk 文档的链接。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-13
  • 1970-01-01
  • 2014-11-26
  • 2016-10-14
相关资源
最近更新 更多