3

次の「basefile.csv」があります

AAM7676,2012-02-02 11:55:52,32,2012-02-03 19:55:30,62,1
AAM7676,2012-02-11 13:56:11,32,2012-02-12 21:00:18,52,2
AAM7676,2012-02-21 16:30:55,32,2012-02-23 13:29:41,62,1
AAM7676,2012-03-07 20:03:32,32,2012-03-09 13:31:35,62,1
AAM7676,2012-05-28 06:08:05,32,2012-05-29 15:49:55,52,2
AAM7676,2012-08-22 12:47:28,32,2012-08-24 08:03:09,52,1
AAO9229,2012-01-10 07:19:29,32,2012-01-11 16:39:16,52,2
AAP0678,2012-04-09 16:35:19,32,2012-04-10 19:46:55,52,2
AAP0678,2012-04-30 16:44:28,32,2012-05-01 19:20:00,52,2
AAP0678,2012-06-01 19:31:34,32,2012-06-03 10:34:33,52,3
AAU6100,2012-01-09 17:49:13,32,2012-01-11 02:00:33,52,3
AAU6100,2012-01-20 21:18:16,32,2012-01-22 14:09:00,52,3
AAU6100,2012-02-20 13:35:39,32,2012-02-21 19:45:55,52,2
AAU6100,2012-03-13 09:50:51,32,2012-03-14 22:35:51,52,3

列 1 (車のプレート) と列 4 (日時) に基づいて、プレート (列 1) が月に何回 (列 4) 発生するかを示す統計を作成したいと思います。

最終的な形式は次のとおりです。

plate,jan,feb,mar,abr,may,jun,jul,aug,sep.oct,nov,dec,total
AAM7676,0,3,1,0,1,0,0,1,0,0,0,0,6
AAO9229,1,0,0,0,0,0,0,0,0,0,0,0,1
AAP0678,0,0,0,1,1,1,0,0,0,0,0,0,3
AAU6100,2,1,1,0,0,0,0,0,0,0,0,0,4

私はすでにそれを解決する方法を理解せずにシェルスクリプトとMySQLで遊んだ(そして解決策を探した)...おそらく私が初心者だから....

あらゆる種類のソリューションを歓迎します (MySQL、sh、perl、python など)。

4

8 に答える 8

4

これは基本的に、 Python Pandasのポスターのような質問です。列ヘッダー名は、license、time1、num1、time2、num2、count (この順序で) であると想定しています。

import pandas, numpy as np
df = pandas.io.parsers.read_csv("baseline.csv")
df["month"] = df["time2"].map(lambda x: int(x.split('-')[1]))
df.groupby(["license","month"]).apply(len)

出力:

license  month
AAM7676  2        3
         3        1
         5        1
         8        1
AAO9229  1        1
AAP0678  4        1
         5        1
         6        1
AAU6100  1        2
         2        1
         3        1

次に、カウントのマルチインデックス Pandas シリーズがあるので、必要に応じて出力テーブルをフォーマットできます。ただし、パンダから直接欲しいものと非常によく似たものをフォーマットして印刷するのはそれほど難しくありません。

t = df.groupby(["license","month"]).apply(len)
t.unstack(level=0).reindex(index=range(1,13), fill_value=0).T.fillna(0)

プリントアウト:

               1   2   3   4   5   6   7   8   9   10  11  12
      license
count AAM7676   0   3   1   0   1   0   0   1   0   0   0   0
      AAO9229   1   0   0   0   0   0   0   0   0   0   0   0
      AAP0678   0   0   0   1   1   1   0   0   0   0   0   0
      AAU6100   2   1   1   0   0   0   0   0   0   0   0   0

このソリューションには、(a) ヘッダー名と (b) 2 つのサードパーティ ライブラリが必要です。それは大きな勝利をもたらします。グループ化された操作を非常に簡単に集約して適用でき、NumPy と同様に最適化されます。これは、必要に応じて、非常に大きなデータや、データを使用して多くの異なる二次統計を計算する場合にうまく機能します。

私は通常、このような答えで撃たれるので、はっきりさせてください。純粋な Python でこれを行う方法を知ることは素晴らしいことであり、Python プログラマーはそれを学ぶために時間をかける必要があります。ただし、Python のためだけに車輪を再発明しないでください。Pandas は、まさにこの種のデータ操作のための優れたツールをいくつか提供しています。

于 2012-09-26T22:38:24.923 に答える
3

次のPythonソリューションが機能するはずです。

import csv
import collections

result = collections.OrderedDict()
for cols in csv.reader(open('basefile.csv')):
    if len(cols) != 6:
        continue
    plate = cols[0]
    month = int(cols[3][5:7])
    result.setdefault(plate, [plate] + [0]*12)[month] += 1

print 'plate,jan,feb,mar,abr,may,jun,jul,aug,sep.oct,nov,dec,total'
for row in result.values():
    print ','.join(map(str, row)) + ',' + str(sum(row[1:]))
于 2012-09-26T22:21:19.377 に答える
3

gawkの使用:

gawk -F, '
    {
        plate[$1]++
        split($4, dt, /-0*/)
        count[$1,dt[2]]++
    }
    END {
        print "plate,jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec,total"
        n = asorti(plate, ordered_plates)
        for (i=1; i<=n; i++) {
            p = ordered_plates[i]
            printf("%s,", p)
            for (m=1; m<=12; m++) 
                printf("%d,", count[p,m])
            print plate[p]
        }
    }
' basefile.csv 

出力

plate,jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec,total
AAM7676,0,3,1,0,1,0,0,1,0,0,0,0,6
AAO9229,1,0,0,0,0,0,0,0,0,0,0,0,1
AAP0678,0,0,0,1,1,1,0,0,0,0,0,0,3
AAU6100,2,1,1,0,0,0,0,0,0,0,0,0,4
于 2012-09-27T00:13:41.523 に答える
3

Perlソリューション。どのフィールドにもコンマが埋め込まれていないことを前提としています。

#!/usr/bin/perl
use strict;
use warnings;
use List::Util qw/ sum /;

my %data;
while (<DATA>) {
    my ($plate, $col4) = (split /,/)[0, 3];
    my ($month) = $col4 =~ /-(\d\d)-/;
    $data{$plate}{$month}++;
}

print join(",", qw/ plate jan feb mar apr may jun jul aug sep oct nov dec total /), "\n";

for my $plate (sort keys %data) {
    my @per_month = map $data{$plate}{$_} || 0, '01' .. '12';
    print join(",", $plate, @per_month, sum @per_month), "\n";
}

__DATA__
AAM7676,2012-02-02 11:55:52,32,2012-02-03 19:55:30,62,1 
AAM7676,2012-02-11 13:56:11,32,2012-02-12 21:00:18,52,2 
AAM7676,2012-02-21 16:30:55,32,2012-02-23 13:29:41,62,1 
AAM7676,2012-03-07 20:03:32,32,2012-03-09 13:31:35,62,1 
AAM7676,2012-05-28 06:08:05,32,2012-05-29 15:49:55,52,2 
AAM7676,2012-08-22 12:47:28,32,2012-08-24 08:03:09,52,1 
AAO9229,2012-01-10 07:19:29,32,2012-01-11 16:39:16,52,2 
AAP0678,2012-04-09 16:35:19,32,2012-04-10 19:46:55,52,2 
AAP0678,2012-04-30 16:44:28,32,2012-05-01 19:20:00,52,2 
AAP0678,2012-06-01 19:31:34,32,2012-06-03 10:34:33,52,3 
AAU6100,2012-01-09 17:49:13,32,2012-01-11 02:00:33,52,3 
AAU6100,2012-01-20 21:18:16,32,2012-01-22 14:09:00,52,3 
AAU6100,2012-02-20 13:35:39,32,2012-02-21 19:45:55,52,2 
AAU6100,2012-03-13 09:50:51,32,2012-03-14 22:35:51,52,3 
于 2012-09-27T00:28:38.690 に答える
1

月の 12 列は RBDS では正確には自然ではありませんが、次の SQL COUNT と GROUP BY はトリックを行います。

drop table if exists toto;
create table toto(
    plate VARCHAR(32),
    date1 DATETIME,
    something1 INT(10),
    date2 DATETIME,
    something2 INT(10),
    something3 INT(10)
);

INSERT INTO toto VALUES('AAM7676','2012-02-02 11:55:52',32,'2012-02-03 19:55:30',62,1);
INSERT INTO toto VALUES('AAM7676','2012-02-11 13:56:11',32,'2012-02-12 21:00:18',52,2);
INSERT INTO toto VALUES('AAM7676','2012-02-21 16:30:55',32,'2012-02-23 13:29:41',62,1);
INSERT INTO toto VALUES('AAM7676','2012-03-07 20:03:32',32,'2012-03-09 13:31:35',62,1);
INSERT INTO toto VALUES('AAM7676','2012-05-28 06:08:05',32,'2012-05-29 15:49:55',52,2);
INSERT INTO toto VALUES('AAM7676','2012-08-22 12:47:28',32,'2012-08-24 08:03:09',52,1);
INSERT INTO toto VALUES('AAO9229','2012-01-10 07:19:29',32,'2012-01-11 16:39:16',52,2);
INSERT INTO toto VALUES('AAP0678','2012-04-09 16:35:19',32,'2012-04-10 19:46:55',52,2);
INSERT INTO toto VALUES('AAP0678','2012-04-30 16:44:28',32,'2012-05-01 19:20:00',52,2);
INSERT INTO toto VALUES('AAP0678','2012-06-01 19:31:34',32,'2012-06-03 10:34:33',52,3);
INSERT INTO toto VALUES('AAU6100','2012-01-09 17:49:13',32,'2012-01-11 02:00:33',52,3);
INSERT INTO toto VALUES('AAU6100','2012-01-20 21:18:16',32,'2012-01-22 14:09:00',52,3);
INSERT INTO toto VALUES('AAU6100','2012-02-20 13:35:39',32,'2012-02-21 19:45:55',52,2);
INSERT INTO toto VALUES('AAU6100','2012-03-13 09:50:51',32,'2012-03-14 22:35:51',52,3);


SELECT 
    t.plate,
    (SELECT COUNT(*) FROM toto tt WHERE tt.plate=t.plate AND EXTRACT(MONTH FROM date1)=1),
    (SELECT COUNT(*) FROM toto tt WHERE tt.plate=t.plate AND EXTRACT(MONTH FROM date1)=2),
    (SELECT COUNT(*) FROM toto tt WHERE tt.plate=t.plate AND EXTRACT(MONTH FROM date1)=3),
    (SELECT COUNT(*) FROM toto tt WHERE tt.plate=t.plate AND EXTRACT(MONTH FROM date1)=4),
    (SELECT COUNT(*) FROM toto tt WHERE tt.plate=t.plate AND EXTRACT(MONTH FROM date1)=5),
    (SELECT COUNT(*) FROM toto tt WHERE tt.plate=t.plate AND EXTRACT(MONTH FROM date1)=6),
    (SELECT COUNT(*) FROM toto tt WHERE tt.plate=t.plate AND EXTRACT(MONTH FROM date1)=7),
    (SELECT COUNT(*) FROM toto tt WHERE tt.plate=t.plate AND EXTRACT(MONTH FROM date1)=8),
    (SELECT COUNT(*) FROM toto tt WHERE tt.plate=t.plate AND EXTRACT(MONTH FROM date1)=9),
    (SELECT COUNT(*) FROM toto tt WHERE tt.plate=t.plate AND EXTRACT(MONTH FROM date1)=10),
    (SELECT COUNT(*) FROM toto tt WHERE tt.plate=t.plate AND EXTRACT(MONTH FROM date1)=11),
    (SELECT COUNT(*) FROM toto tt WHERE tt.plate=t.plate AND EXTRACT(MONTH FROM date1)=12),
    COUNT(*)
FROM toto t
GROUP BY plate;

結果 :

AAM7676 0   3   1   0   1   0   0   1   0   0   0   0   6
AAO9229 1   0   0   0   0   0   0   0   0   0   0   0   1
AAP0678 0   0   0   2   0   1   0   0   0   0   0   0   3
AAU6100 2   1   1   0   0   0   0   0   0   0   0   0   4
于 2012-09-26T23:15:00.770 に答える
1

リストの辞書を保持します。

from collections import defaultdict
d = defaultdict(lambda : [None]+[0]*12)

with open('yourfile') as f:
    for line in f:
        plate,_,_,time,_,_ = line.split(',')  #maybe use csv instead
        month = int(time.split('-')[1])       #get the month
        d[plate][month] += 1
于 2012-09-26T22:25:49.437 に答える
1

ステージ 1: プレートと年月を含むエントリを生成する

cut -d, -f1,4 basefile.csv |
sed 's/,2012-\([0-9][0-9]\)-[0-9][0-9] ..:..:..$/ \1/'

これは、日付がすべて 2012 年であることを前提としており、カンマ区切りをスペースにマップします。

出力例:

AAM7676 02
AAM7676 02
AAM7676 02
AAM7676 03
AAM7676 05
AAM7676 08
AAO9229 01
AAP0678 04
AAP0678 05
AAP0678 06
AAU6100 01
AAU6100 01
AAU6100 02
AAU6100 03

ステージ 2: 1 か月あたりのカウントを生成する

... |
sort | uniq -c

出力例:

3 AAM7676 02
1 AAM7676 03
1 AAM7676 05
1 AAM7676 08
1 AAO9229 01
1 AAP0678 04
1 AAP0678 05
1 AAP0678 06
2 AAU6100 01
1 AAU6100 02
1 AAU6100 03

ステージ 3: ピボット

データは、プレート、月の順です。この時点で、次のようawkにしてコントロール ブレーク レポートを作成します。

cut -d, -f1,4 basefile.csv |
sed 's/,2012-\([0-9][0-9]\)-[0-9][0-9] ..:..:..$/ \1/' |
sort |
uniq -c |
awk '
    {   if ($2 != last_plate && last_plate != "")
        {
            printf "%s", last_plate
            for (i = 1; i <= 12; i++)
            {
                printf ",%d", count[i]
                count[i] = 0;
            }
            print ""
        }
        last_plate = $2
        count[$3+0] = $1
    }
    END {   if (last_plate != "")
            {
                printf "%s", last_plate
                for (i = 1; i <= 12; i++)
                    printf ",%d", count[i]
                print ""
            }
    }'

そこにある唯一の「トリック」は添え字count[$3+0]です。これは、 などの文字列01を添え字の純粋な数値 1 に変換します。

サンプル データの出力は次のとおりです。

AAM7676,0,3,1,0,1,0,0,1,0,0,0,0
AAO9229,1,0,0,0,0,0,0,0,0,0,0,0
AAP0678,0,0,0,1,1,1,0,0,0,0,0,0
AAU6100,2,1,1,0,0,0,0,0,0,0,0,0

列ヘッダーも必要な場合は、スクリプトにBEGIN ブロックと適切なprintステートメントを簡単に追加するだけです。awk

それはすべてで行うことができawkますか? おそらく...私のゲストになります。並べ替えは唯一のトリッキーなビットです。また、Perl、Python、またはその他の同様のスクリプト言語ですべて実行することもできます。

于 2012-09-26T22:42:34.687 に答える
1

このクエリを試してください -

SELECT
  plate,
  COUNT(IF(MONTH(dt2) = 1, 1, NULL)) jan,
  COUNT(IF(MONTH(dt2) = 2, 1, NULL)) feb,
  COUNT(IF(MONTH(dt2) = 3, 1, NULL)) mar,
  COUNT(IF(MONTH(dt2) = 4, 1, NULL)) apr,
  COUNT(IF(MONTH(dt2) = 5, 1, NULL)) may,
  COUNT(*) total
FROM
  basefile_table
WHERE
  YEAR(dt2) = 2012
GROUP BY
  plate;

+---------+-----+-----+-----+-----+-----+-------+
| plate   | jan | feb | mar | apr | may | total |
+---------+-----+-----+-----+-----+-----+-------+
| AAM7676 |   0 |   3 |   1 |   0 |   1 |     6 |
| AAO9229 |   1 |   0 |   0 |   0 |   0 |     1 |
| AAP0678 |   0 |   0 |   0 |   1 |   1 |     3 |
| AAU6100 |   2 |   1 |   1 |   0 |   0 |     4 |
+---------+-----+-----+-----+-----+-----+-------+

他の月を追加 - 6 月、7 月、... 注: クエリに年フィルターを追加しました。

于 2012-09-27T06:40:08.350 に答える