テキストファイルの数値の累積累計をどのように生成しますか?


9

200万行のテキストファイルがあります。各行には正の整数があります。度数表のようなものを作ろうとしています。

入力ファイル:

3
4
5
8

出力は次のようになります。

3
7
12
20

これを行うにはどうすればよいですか?


1
あなたのテキストでは、あなたは頻度が必要だと言っています。出力サンプルはリストです。これを明確にしていただけますか?
Wayne_Yux 2017

実際、あなたの出力は頻度表ではありません
don.joey

申し訳ありません。累積度数表という意味です。質問を変更しました。ありがとう。

あまりクールではありませんが、通常はこのようなことをスプレッドシートに行います。
John U、

@JohnU私は通常そうしますが、私が持っているファイルには100万の数値があります。

回答:


20

awk

awk '{total += $0; $0 = total}1'

$0現在の行です。したがって、各行について、それをに追加しtotal、行をnewに設定するtotalと、末尾1がawkショートカットに1なります。これは、すべてのtrue条件の現在の行を出力し、条件がtrueと評価されるときに出力します。


コードについて説明していただけますか?
ジョージウドセン2017

その言葉printも使えますか?
ジョージウドセン2017

はい、print total}代わりに$0 = total}1
muru

1
@ジョージああ、いいえ。
muru

9
awkスクリプトを作成するより短く、おそらくより理解しやすい方法は{print(total += $0)}
Miles

9

Pythonスクリプト:

#!/usr/bin/env python3
import sys

f = sys.argv[1]; out = sys.argv[2]

n = 0

with open(out, "wt") as wr:
    with open(f) as read:
        for l in read:
            n = n + int(l); wr.write(str(n)+"\n")

使用するには

  • スクリプトを空のファイルにコピーし、名前を付けて保存します add_last.py
  • 引数としてソースファイルとターゲットの出力ファイルを指定して実行します。

    python3 /path/to/add_last.py <input_file> <output_file>
    

説明

コードはかなり読みやすいですが、詳細には:

  • 結果を書き込むために出力ファイルを開く

    with open(out, "wt") as wr:
    
  • 入力ファイルを開いて1行ごとに読み取る

    with open(f) as read:
        for l in read:
    
  • 行を読み、合計に新しい行の値を追加します。

    n = n + int(l)
    
  • 結果を出力ファイルに書き込みます。

    wr.write(str(n)+"\n")
    


3
短さや時間のパフォーマンスについてではありません(100万行はビッグデータではありません)。あなたの答えのコードは慣用的なPythonではありません。私の答えは、あなたのPythonicバージョンです。
jfs

8
@JFSebastianより慣用的なバージョンの方が遅い場合、なぜそれを好むのですか?「Pythonic」であることには特別なことは何もありません。これは、Python開発者が読みやすさのためにコードと標準を共有するのに役立つ規則にすぎません。より慣用的なバージョンの方が効率が悪い(遅い)場合は、標準化がパフォーマンスよりも重要な環境で作業している場合を除いて、使用しないでください(これは恐ろしい考えのように聞こえます)。
terdon 2017

2
@terdon時期尚早な最適化について言うべきことがある。長期的な保守性のため、読みやすさが重要になる場合があります。
muru

4
@muru確かに、これは完全に読みやすいです。犯罪は「pythonic」ではないということだけです。言うまでもなく、私たちは7行のコードについて話しているのであって、いくつかの巨大なプロジェクトについて話しているのではありません。スタイル規約の名前の効率を犠牲にすることは、間違ったアプローチのようです。
terdon 2017

9

楽しみのためだけに

$ sed 'a+p' file | dc -e0 -
3
7
12
20

これは、ことによって動作ppending 入力の各ラインに、その後に結果を渡す場合電卓+pdc

   +      Pops two values off the stack, adds them, and pushes the result.
          The precision of the result is determined only by the values  of
          the arguments, and is enough to be exact.

その後

   p      Prints  the  value on the top of the stack, without altering the
          stack.  A newline is printed after the value.

-e0引数はプッシュ0dc合計を初期化するためにスタック。


このようなものは、実際には大規模なデータセットよりも高速かもしれません
Digital Trauma

130万行の@DigitalTrauma、実際にはほとんど最も遅い:real 0m4.234s
Jacob Vlijm

楽しみは
賛成投票

少し説明してください。
AmanicA 2017

8

バッシュで:

#! /bin/bash

file="YOUR_FILE.txt"

TOTAL=0
while IFS= read -r line
do
    TOTAL=$(( TOTAL + line ))
    echo $TOTAL
done <"$file"

bashはこれに関して非常に遅いです:real 0m53.116s、ほぼ1分、130万行で:)
Jacob Vlijm

@JacobVlijmダッシュは、busybox ashおよびzsh(shモードの場合)の約2倍の速度ですが、もちろん、ダッシュよりもpythonの5倍遅いです。
muru

6

標準入力で指定された整数の部分合計を1行に1つずつ出力するには:

#!/usr/bin/env python3
import sys

partial_sum = 0
for n in map(int, sys.stdin):
    partial_sum += n
    print(partial_sum)

実行可能な例

何らかの理由でコマンドが遅すぎる場合。Cプログラムを使用できます。

#include <stdint.h>
#include <ctype.h>
#include <stdio.h>

int main(void)
{
  uintmax_t cumsum = 0, n = 0;
  for (int c = EOF; (c = getchar()) != EOF; ) {
    if (isdigit(c))
      n = n * 10 + (c - '0');
    else if (n) { // complete number
      cumsum += n;
      printf("%ju\n", cumsum);
      n = 0;
    }
  }
  if (n)
    printf("%ju\n", cumsum + n);
  return feof(stdin) ? 0 : 1;
}

ビルドして実行するには、次のように入力します。

$ cc cumsum.c -o cumsum
$ ./cumsum < input > output

実行可能な例

UINTMAX_MAXです18446744073709551615

Cコードは、私のマシンで生成された入力ファイルのawkコマンドよりも数倍高速です。

#!/usr/bin/env python3
import numpy.random
print(*numpy.random.random_integers(100, size=2000000), sep='\n')


5

あなたはおそらくこのようなものを望みます:

sort -n <filename> | uniq -c | awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}'

コマンドの説明:

  • sort -n <filename> | uniq -c 入力をソートし、頻度表を返します
  • | awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}' ooutputをより良いフォーマットに変換します

例:
入力ファイルlist.txt

4
5
3
4
4
2
3
4
5

コマンド:

$ sort -n list.txt | uniq -c | awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}'
Number  Frequency
2   1
3   2
4   4
5   2

私はこれが好きです出力は素晴らしいです:)...
ジョージUdosen

5

あなたはvimでこれを行うことができます。ファイルを開き、次のキーストロークを入力します。

qaqqayiwj@"<C-a>@aq@a:wq<cr>

<C-a>実際にはCTRL-あり、そして<cr>あるキャリッジリターン、すなわちボタンを入力してください。

これがどのように機能するかです。まず、レジスタ「a」をクリアして、初回の副作用がないようにします。これは単にqaqです。次に、以下を実行します。

qa                  " Start recording keystrokes into register 'a'
  yiw               " Yank this current number
     j              " Move down one line. This will break the loop on the last line
      @"            " Run the number we yanked as if it was typed, and then
        <C-a>       " increment the number under the cursor *n* times
             @a     " Call macro 'a'. While recording this will do nothing
               q    " Stop recording
                @a  " Call macro 'a', which will call itself creating a loop

この再帰的なマクロの実行が完了:wq<cr>したら、単純に保存して終了するように呼び出します。


1
魔法の呪文を分解し、すべての部分を説明するための+1。これらの部品の周りはあまりにもまれです。
John U、

5

Perlワンライナー:

$ perl -lne 'print $sum+=$_' input.txt                                                                
3
7
12
20

250万行の数値を使用すると、処理に約6.6秒かかります。

$ time perl -lne 'print $sum+=$_' large_input.txt > output.txt                                        
    0m06.64s real     0m05.42s user     0m00.09s system

$ wc -l large_input.txt
2500000 large_input.txt

real 0m0.908s、 けっこういい。
Jacob Vlijm 2017

かなり小さいファイルにある@JacobVlijm。250万行のファイルを含む小さなテストを追加しました。6.64秒
セルギーコロディアズニー

1
私は古代のシステムで130万行を実行しました
Jacob Vlijm 2017

3

単純なBashワンライナー:

x=0 ; while read n ; do x=$((x+n)) ; echo $x ; done < INPUT_FILE

x現在の行以上のすべての数値の累計です。
n現在の行の番号です。

我々は、すべての行をループnINPUT_FILEと私たちの変数にその数値を追加xし、各反復中にその合計を印刷します。

Bashはここでは少し遅いですが、200万エントリのファイルの場合、出力をコンソールに出力せずに、20〜30秒程度かかると予想できます(使用する方法に関係なく、さらに遅くなります)。


3

@steeldriverの答えに似ていますが、bc代わりに難解さが少し減っています。

sed 's/.*/a+=&;a/' input | bc

bc(およびdc)の良い点は、これらが任意精度の計算機であるため、オーバーフローしたり、整数の精度が不足したりすることがないことです。

sed式はに入力を変換します。

a+=3;a
a+=4;a
a+=5;a
a+=8;a

これは次にによって評価されbcます。のaBC変数は、自動初期化各ラインずつ0にはa、次に明示的に印刷します。


real 0m5.642s130万行。sedはこれに関して本当に遅いです。
Jacob Vlijm 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.