从非平面文件处理文本(以提取信息,就好像它是* *平面文件)
-
20-09-2019 - |
题
我具有由可通过以下的表(“变种”是变量)来表示的计算机模拟产生的纵向数据集:
time subject var1 var2 var3
t1 subjectA ...
t2 subjectB ...
和
subject name
subjectA nameA
subjectB nameB
然而,生成的文件写入的格式类似于以下的数据文件:
time t1
description
subjectA nameA
var1 var2 var3
subjectB nameB
var1 var2 var3
time t2
description
subjectA nameA
var1 var2 var3
subjectB nameB
var1 var2 var3
...(and so on)
我已使用(蟒)脚本来处理此输出数据转换为纯文本文件,这样我可以将其导入到R,蟒,SQL,或AWK / grep的它提取信息 - 的类型的一个例子从单个查询所需的信息(在SQL符号,该数据被转换为表格后)如下所示:
SELECT var1, var2, var3 FROM datatable WHERE subject='subjectB'
我不知道是否有一个更有效的解决方案,因为每个这些数据文件的可〜100MB每个(我有数百人)和创建平面文本文件是费时且占用具有冗余额外的硬盘驱动器空间信息。理想情况下,我会与原始数据集直接提取我的愿望的信息交互,而无需创建额外的纯文本文件?有没有这样的任务,这是简单的一个awk / perl的解决方案吗?我在文字处理在Python相当精通,但我在AWK技能是最基本的,我有Perl的没有工作经验;我不知道这些或其它特定领域的工具,可以提供更好的解决方案。
谢谢!
<强>后记:强> 哇,谢谢大家!我很抱歉,我不能选择每个人的答案 @FM:谢谢。我的Python脚本就像你的代码,而无需过滤步骤。但是,你的组织是干净的。 @PP:我想我已经在grep的熟练但显然不是!这是非常有帮助的......但我认为混合“时间”到输出时grepping变得困难(我没有包括在我的例子可能的提取方案!这是我的坏)。 @ ghostdog74:这真是太棒了......但修改了这一行获得“subjectA”并不简单......(虽然我会在此期间更AWK读了,希望我以后神交)。 @weismat:恩说。 @美国洛特:这是非常优雅和灵活的 - 我不是问了一个Python(IC)解决方案,但这种清洁适合在与解析,过滤器和输出框架,PP建议,并具有足够的灵活性,以适应一些不同的查询,从这个层次文件中提取不同类型的信息。
,我再次感谢大家 - 非常感谢
解决方案
这是什么Python生成的全部意义。
def read_as_flat( someFile ):
line_iter= iter(someFile)
time_header= None
for line in line_iter:
words = line.split()
if words[0] == 'time':
time_header = [ words[1:] ] # the "time" line
description= line_iter.next()
time_header.append( description )
elif words[0] in subjectNameSet:
data = line_iter.next()
yield time_header + data
可以使用该像标准的Python迭代
for time, description, var1, var2, var3 in read_as_flat( someFile ):
etc.
其他提示
如果你想要的是VAR1,VAR2,VAR3在匹配特定的主题,那么你可以尝试下面的命令:
grep -A 1 'subjectB'
在-A 1
命令行参数指示grep来打印出匹配线后的匹配线和一条线(在此情况下,变量来对所述受试者后的线)。
您可能需要使用-E
选项,以使对正则表达式的grep搜索和锚定对象搜索开始的行(例如grep -A 1 -E '^subjectB'
)。
最后输出将由目前你想要的主题行和变线的。您可能希望隐藏主题行:
grep -A 1 'subjectB' |grep -v 'subjectB'
和你可能希望处理该变量的行:
grep -A 1 'subjectB' |grep -v 'subjectB' |perl -pe 's/ /,/g'
在最好的办法是修改计算机仿真,以产生矩形输出。假设你不能做到这一点,这里有一个方法:
为了能够使用R,SQL,等需要将其从分级转换数据到矩形这种或那种方式。如果你已经有了一个解析器,可以把整个文件转换成一个长方形的数据集,你最那里的方式。接下来的步骤是额外的灵活性添加到您的解析器,以便它可以过滤掉不需要的数据记录。相反,具有文件转换器,你将有一个数据抽取工具。
下面的例子是在Perl,但你可以做同样的事情在Python。总的想法是保持(a)中解析,(b)过滤,和(c)输出之间的清晰分离。这样一来,你有一个灵活的环境,因此很容易添加不同的过滤或输出方式,取决于你的即时数据处理需求。也可以设置过滤的方法来接受的参数(无论是从命令行或配置文件),用于更大的灵活性。
use strict;
use warnings;
read_file($ARGV[0], \&check_record);
sub read_file {
my ($file_name, $check_record) = @_;
open(my $file_handle, '<', $file_name) or die $!;
# A data structure to hold an entire record.
my $rec = {
time => '',
desc => '',
subj => '',
name => '',
vars => [],
};
# A code reference to get the next line and do some cleanup.
my $get_line = sub {
my $line = <$file_handle>;
return unless defined $line;
chomp $line;
$line =~ s/^\s+//;
return $line;
};
# Start parsing the data file.
while ( my $line = $get_line->() ){
if ($line =~ /^time (\w+)/){
$rec->{time} = $1;
$rec->{desc} = $get_line->();
}
else {
($rec->{subj}, $rec->{name}) = $line =~ /(\w+) +(\w+)/;
$rec->{vars} = [ split / +/, $get_line->() ];
# OK, we have a complete record. Now invoke our filtering
# code to decide whether to export record to rectangular format.
$check_record->($rec);
}
}
}
sub check_record {
my $rec = shift;
# Just an illustration. You'll want to parameterize this, most likely.
write_output($rec)
if $rec->{subj} eq 'subjectB'
and $rec->{time} eq 't1'
;
}
sub write_output {
my $rec = shift;
print join("\t",
$rec->{time}, $rec->{subj}, $rec->{name},
@{$rec->{vars}},
), "\n";
}
如果你是懒惰的,并有足够的内存,那么我会RAM磁盘,而不是在文件系统上,只要你马上需要他们的工作。结果 我不认为Perl或awk将是比Python更快,如果你是刚刚重新编码当前的算法成不同的语言。
awk '/time/{f=0}/subjectB/{f=1;next}f' file