查找列中的唯一值并将唯一值替换为数字

Posted

技术标签:

【中文标题】查找列中的唯一值并将唯一值替换为数字【英文标题】:Find the unique values in a column and replace the unique values with numbers 【发布时间】:2014-06-27 07:07:29 【问题描述】:

我有一个标签限制数据,显示为

1 0 0 1 1 Black Swan
0 0 1 0 0 Golden Duck
1 0 0 1 0 Brown Eagle
0 0 1 0 1 Golden Duck
1 0 0 1 0 Black Swan
1 0 1 0 0 Golden Duck
1 0 0 1 1 Sparrow

最后一列是由空格分隔的一个或多个单词的组合。我想计算最后一列中唯一值的数量,并将其替换为该组唯一的数字。我知道我可以计算并列出数字使用

awk -F '\t' 'print $NF'  infile | sort | uniq | wc -l

但是如何用数字替换? 例如,将所有 Black Swan 替换为 1,将所有 Golden Duck 替换为 2 等等。我希望结果是:

1 0 0 1 1 1
0 0 1 0 0 2
1 0 0 1 0 3
0 0 1 0 1 2
1 0 0 1 0 1
1 0 1 0 0 2
1 0 0 1 1 4

我还想生成赋予特定值的数字列表,例如

Black Swan 1
Golden Duck 2
Brown Eagle 3
Sparrow 4

【问题讨论】:

【参考方案1】:

您可以使用关联数组为每个不同的名称增加一个计数器:

awk '
    BEGIN  
        FS = OFS = "\t" 
        i = 0
    
    
        if (! names[$NF]) 
            names[$NF] = ++i
        
        $NF = names[$NF]
        print $0
    
    END 
        for (name in names) 
            printf "%s %d\n", name, names[name]
        
    
' infile

它产生:

1       0       0       1       1       1
0       0       1       0       0       2
1       0       0       1       0       3
0       0       1       0       1       2
1       0       0       1       0       1
1       0       1       0       0       2
1       0       0       1       1       4
Golden Duck 2
Brown Eagle 3
Sparrow 4
Black Swan 1

【讨论】:

同意。显然不需要初始化i,最后的printf可能只是打印但nbd。【参考方案2】:

我开始写这个,所以我会完成:

awk '
BEGIN FS = OFS = "\t"

    last[$NF] = (last[$NF] ? last[$NF] : ++cnt)
    $NF = last[$NF]
    line[NR] = $0

END 
    for (nr=1; nr<=NR; nr++) 
        print line[nr]
    for (name in last) 
        print name, last[name]
' file
1       0       0       1       1       1
0       0       1       0       0       2
1       0       0       1       0       3
0       0       1       0       1       2
1       0       0       1       0       1
1       0       1       0       0       2
1       0       0       1       1       4
Brown Eagle     3
Black Swan      1
Sparrow         4
Golden Duck     2

更新:

这里是perl 备用:

perl -F'\t' -lane '
    $h$F[-1] = ++$c unless exists $h$F[-1]; 
    $F[-1] = $h$F[-1]; 
    print join "\t", @F  print "$_  $h$_" for keys %h
' file
1       0       0       1       1       1
0       0       1       0       0       2
1       0       0       1       0       3
0       0       1       0       1       2
1       0       0       1       0       1
1       0       1       0       0       2
1       0       0       1       1       4
Golden Duck  2
Brown Eagle  3
Black Swan  1
Sparrow  4

这是基于mpapec's优秀评论的另一个更新:

perl -F'\t' -lane '
    $F[-1] = $h$F[-1] ||= ++$c; 
    print join "\t", @F  print "$_  $h$_" for keys %h
' file 

【讨论】:

+1,只是$h$F[-1] = $h$F[-1] ? $h$F[-1] : ++$c;可以写成$h$F[-1] = $h$F[-1] || ++$c;或简称$h$F[-1] ||= ++$c;splice @F, -1, 1, $h$F[-1];写成$F[-1] = $h$F[-1]。仅用于高尔夫目的,可以进一步缩短$F[-1] = $h$F[-1] ||= ++$c; 谢谢@mpapec,看起来真的很棒。将更新答案。【参考方案3】:

您要做的是创建一组独特的数据。 set 是具有所有唯一元素的字典或哈希表。创建集合后,您可以搜索它并将字符串替换为适当的值。

这里是另一个可以帮助您的套装链接:

http://world.std.com/~swmcd/steven/perl/pm/set.html

【讨论】:

以上是关于查找列中的唯一值并将唯一值替换为数字的主要内容,如果未能解决你的问题,请参考以下文章

如何根据散列中的键/值查找键/值数据并将其添加到 Redis 中的散列?

PSQL - 查找所有值并根据另一列中的非唯一值使其唯一

Pandas,对于一列中的每个唯一值,在另一列中获取唯一值

如何用 0 替换 varchar 列中的所有非数字值

在每一行中从多个不同的列中查找唯一值

MySQL - 如何根据另一列中的唯一值转置一列中的单元格?