【问题标题】:How can I parse a tab separated data file and group the extracted data in Perl?如何解析制表符分隔的数据文件并在 Perl 中对提取的数据进行分组?
【发布时间】:2012-01-13 03:50:43
【问题描述】:

我是 Perl 的新手。我需要解析一个制表符分隔的文本文件。例如:

From name   To name      Timestamp                 Interaction
a             b        Dec  2 06:40:23 IST 2000        comment
c             d        Dec  1 10:40:23 IST 2001          like
e             a        Dec  1 16:03:01 IST 2000         follow
b             c        Dec  2 07:50:29 IST 2002         share
a             c        Dec  2 08:50:29 IST 2001        comment
c             a        Dec 11 12:40:23 IST 2008          like
e             c        Dec  2 07:50:29 IST 2000         like
c             b        Dec 11 12:40:23 IST 2008        follow
b             a        Dec  2 08:50:29 IST 2001        share

解析后,我需要根据用户交互创建组。在这个例子中

a<->b
b<->a
c<->a
a<->c
b<->c
c<->b

为此,我们可以创建一个组。我们需要显示组列表。 我需要一些关于如何解析文件和表单组的指示?

编辑 约束-> 创建组至少需要 3 个用户。 交互只不过是两个用户之间进行的一些通信。什么沟通都无所谓

我的解决方法是

  1. 我们删除了用户之间的重复交互。例如“ab like”,如果存在“ab follow”,那么我们删除这一行。

  2. 创建存储交互两个用户的二维数组,即

              To Name   a       b        c          d
    

    From Name

       a                X       <>       <>         X
       b                <>      X        <>         X
       c                <>      <>       X          X 
       d                X       <>       X          X
    

    X= 表示没有交互 = 表示交互

在这种方法中,我们从第一行开始,即“a”用户检查“b”。如果“a”与“b”交互,那么我们执行反向操作,即“b”与“a”交互。对每一列执行相同的步骤。

但这种方法取决于用户数量。如果存在 1000 个用户,那么我们必须创建 1000 X 1000 矩阵。有没有办法解决这个问题

我已添加示例输入

a   c   Dec  2 06:40:23 IST 2000    comment
f   g   Dec  2 06:40:23 IST 2009    like
c   a   Dec  2 06:40:23 IST 2009    like
g   h   Dec  2 06:40:23 IST 2008    like
a   d   Dec  2 06:40:23 IST 2008    like
r   t   Dec  2 06:40:23 IST 2007    share
d   a   Dec  2 06:40:23 IST 2007    share
t   u   Dec  2 06:40:23 IST 2006    follow
a   e   Dec  2 06:40:23 IST 2006    follow
k   l   Dec  2 06:40:23 IST 2009    like
e   a   Dec  2 06:40:23 IST 2009    like
j   k   Dec  2 06:40:23 IST 2003    like
c   d   Dec  2 06:40:23 IST 2003    like
l   j   Dec  2 06:40:23 IST 2002    like
d   c   Dec  2 06:40:23 IST 2002    like
m   n   Dec  2 06:40:23 IST 2005    like
c   e   Dec  2 06:40:23 IST 2005    like
m   l   Dec  2 06:40:23 IST 2011    like
e   c   Dec  2 06:40:23 IST 2011    like
h   j   Dec  2 06:40:23 IST 2010    like
d   e   Dec  2 06:40:23 IST 2010    like
o   p   Dec  2 06:40:23 IST 2009    like
e   d   Dec  2 06:40:23 IST 2009    like
p   q   Dec  2 06:40:23 IST 2000    comment
q   p   Dec  2 06:40:23 IST 2009    like
a   p   Dec  2 06:40:23 IST 2008    like    
p   a   Dec  2 06:40:23 IST 2007    share
l   p   Dec  2 06:40:23 IST 2003    like
j   l   Dec  2 06:40:23 IST 2002    like
t   r   Dec  2 06:40:23 IST 2000    comment
r   h   Dec  2 06:40:23 IST 2009    like
j   f   Dec  2 06:40:23 IST 2008    like    
g   d   Dec  2 06:40:23 IST 2007    share
w   q   Dec  2 06:40:23 IST 2003    like
o   y   Dec  2 06:40:23 IST 2002    like
x   y   Dec  2 06:40:23 IST 2000    comment
y   x   Dec  2 06:40:23 IST 2009    like
x   z   Dec  2 06:40:23 IST 2008    like    
z   x   Dec  2 06:40:23 IST 2007    share
y   z   Dec  2 06:40:23 IST 2003    like
z   y   Dec  2 06:40:23 IST 2002    like

输出应该是:

(a,c, d, e)
(x,y,z)

【问题讨论】:

  • 那里至少存在三个不同的问题(读取文件、从中提取数据、构建数据)。哪一个给你带来了问题?
  • 你试过什么?它怎么没有像你预期的那样工作?你被困在哪里了?
  • @Quentin:感谢您的快速回复。我被困在结构化数据上。
  • @sarnold 我是 perl 新手。如何处理用户和表单组的交互。
  • 您是否遇到了 Perl 问题或数据本身的结构化问题?我看不到您想要的数据的详细结构。您想创建“基于用户交互的组”,交互显示在您的示例结果中。你的数据有'from'和'to',但你的输出有'ab',这对我来说意味着'a'与'b'进行交互,'b'对'a'做同样的事情,但是a ->b 是评论,a

标签: perl graph


【解决方案1】:

解析很容易。一个split /\t/ 可能就足够了。不过,Text::xSVText::CSV 可能会更好。

对于连接,您可以使用Graph 模块。为了能够有效地使用该模块,您至少需要了解graph theory 的基础知识。

请注意,strongly connected component 定义为:

如果从图中的每个顶点到每个其他顶点都有一条路径,则称为有向图。特别是,这意味着每个方向的路径;从ab 的路径以及从ba 的路径。

有向图 G 的强连通分量是它的最大强连通子图。

但是,请注意,如果您有 a &lt;-&gt; bb &lt;-&gt; cabc 将形成一个强连接组件,这意味着该要求比与之交互的组的所有成员都弱双向的。

我们仍然可以使用它来减少搜索空间。一旦有了候选组,您就可以检查每个组以查看它是否符合您对组的定义。如果候选组不符合您的要求,那么您可以检查所有子集的成员少一个。如果您在其中找不到任何组,则可以查看所有成员少两个的子集,依此类推,直到达到最小组大小限制。

下面的脚本使用了这个想法。但是,它很可能不会扩展。我强烈怀疑一个人可能能够组合一些 SQL 魔法,但我的思想太有限了。

#!/usr/bin/env perl

use strict;
use warnings;

use Graph;
use Algorithm::ChooseSubsets;

use constant MIN_SIZE => 3;

my $interactions = Graph->new(
    directed => 1,
);

while (my $interaction = <DATA>) {
    last unless $interaction =~ /\S/;
    my ($from, $to) = split ' ', $interaction, 3;

    $interactions->add_edge($from, $to);
}

my @groups = map {
    is_group($interactions, $_) ? $_
                                : check_subsets($interactions, $_)
} grep @$_ >= MIN_SIZE, $interactions->strongly_connected_components;


print "Groups: \n";
print "[ @$_ ]\n" for @groups;

sub check_subsets {
    my ($graph, $candidate) = @_;

    my @groups;
    for my $size (reverse MIN_SIZE .. (@$candidate - 1)) {
        my $subsets = Algorithm::ChooseSubsets->new(
            set => $candidate,
            size => $size,
        );

        my $groups_found;
        while (my $subset = $subsets->next) {
            if (is_group($interactions, $subset)) {
                ++$groups_found;
                push @groups, $subset;
            }
        }
        last if $groups_found;
    }

    return @groups;
}

sub is_group {
    my ($graph, $candidate) = @_;

    for my $member (@$candidate) {
        for my $other (@$candidate) {
            next if $member eq $other;
            return unless $graph->has_edge($member, $other);
            return unless $graph->has_edge($other, $member);
        }
    }

    return 1;
}

__DATA__
a   c   Dec  2 06:40:23 IST 2000    comment
f   g   Dec  2 06:40:23 IST 2009    like
c   a   Dec  2 06:40:23 IST 2009    like
g   h   Dec  2 06:40:23 IST 2008    like
a   d   Dec  2 06:40:23 IST 2008    like
r   t   Dec  2 06:40:23 IST 2007    share
d   a   Dec  2 06:40:23 IST 2007    share
t   u   Dec  2 06:40:23 IST 2006    follow
a   e   Dec  2 06:40:23 IST 2006    follow
k   l   Dec  2 06:40:23 IST 2009    like
e   a   Dec  2 06:40:23 IST 2009    like
j   k   Dec  2 06:40:23 IST 2003    like
c   d   Dec  2 06:40:23 IST 2003    like
l   j   Dec  2 06:40:23 IST 2002    like
d   c   Dec  2 06:40:23 IST 2002    like
m   n   Dec  2 06:40:23 IST 2005    like
c   e   Dec  2 06:40:23 IST 2005    like
m   l   Dec  2 06:40:23 IST 2011    like
e   c   Dec  2 06:40:23 IST 2011    like
h   j   Dec  2 06:40:23 IST 2010    like
d   e   Dec  2 06:40:23 IST 2010    like
o   p   Dec  2 06:40:23 IST 2009    like
e   d   Dec  2 06:40:23 IST 2009    like
p   q   Dec  2 06:40:23 IST 2000    comment
q   p   Dec  2 06:40:23 IST 2009    like
a   p   Dec  2 06:40:23 IST 2008    like
p   a   Dec  2 06:40:23 IST 2007    share
l   p   Dec  2 06:40:23 IST 2003    like
j   l   Dec  2 06:40:23 IST 2002    like
t   r   Dec  2 06:40:23 IST 2000    comment
r   h   Dec  2 06:40:23 IST 2009    like
j   f   Dec  2 06:40:23 IST 2008    like
g   d   Dec  2 06:40:23 IST 2007    share
w   q   Dec  2 06:40:23 IST 2003    like
o   y   Dec  2 06:40:23 IST 2002    like
x   y   Dec  2 06:40:23 IST 2000    comment
y   x   Dec  2 06:40:23 IST 2009    like
x   z   Dec  2 06:40:23 IST 2008    like
z   x   Dec  2 06:40:23 IST 2007    share
y   z   Dec  2 06:40:23 IST 2003    like
z   y   Dec  2 06:40:23 IST 2002    like

输出:

组:
[yzx]
[e d a c]

【讨论】:

  • Unur:感谢您的指点。但是我们如何使用图形进行逻辑表示。我是图形和 perl 的新手。
  • Unur :例如,谢谢。我会试试看。创建组的标准“组中的每个用户都必须与该组中的所有其他用户进行双向交互(形成组需要至少 3 个用户)。即如果交互发生在 a->b ; b ->a ; a -> c ; c->a; c->b; b->c 然后我们可以创建组为 (a,b,c)。
  • 在您的输出中显示 (s, q)。但是在您的输入文件中,s 到 q 之间存在交互,而不是从 q 到 s。并且至少需要 3 个用户来组成组。
  • 对不起,我应该提到有问题的“编辑”。感谢您的建议,我将研究 perl graph 的实现。
  • 对不完整的要求道歉,而且我是 perl 的新手。如果您为我提供任何有向图(用户之间的双向交互)的方法,这对我来说将是很大的帮助。您的努力将不胜感激。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-16
  • 1970-01-01
  • 2012-08-19
  • 1970-01-01
  • 2012-12-22
  • 1970-01-01
  • 2016-05-21
相关资源
最近更新 更多