質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

Q&A

解決済

2回答

7064閲覧

[VB] DataTableによる平均値の算出

inukujira

総合スコア130

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

0グッド

1クリップ

投稿2015/07/14 05:42

編集2015/07/14 05:49

以下のテキストファイルがあります。

[test.txt]

lang

12015/07/13 00:00:00, 1 22015/07/13 00:00:01, 2 32015/07/13 00:00:02, 3 42015/07/13 00:01:00, 1 52015/07/13 00:01:01, 2 62015/07/13 00:01:02, 3 7…(省略:実際には24時間分の1秒毎データがあります。)

これを次のように、DataTableへセットしました。

lang

1no,date,value 20,2015/07/13 00:00:00,1 31,2015/07/13 00:00:01,2 42,2015/07/13 00:00:02,3 53,2015/07/13 00:01:00,1 64,2015/07/13 00:01:01,2 75,2015/07/13 00:01:02,3 8…(省略)

行いたい事はdata"2015/07/13 00:00"の"value"平均値を算出したいです。
(要は1秒間隔で出力された値を1分間隔毎に平均値を取得したい)

DataTableに入れる事までは出来ました。

lang

1Dim MyDB As New DataTable 2Dim no As Integer = 0 3 4With MyDB 5 .PrimaryKey = New DataColumn() {.Columns.Add("no", Type.GetType("System.Int32"))} 6 .Columns.Add("date", Type.GetType("System.DateTime")) 7 .Columns.Add("value", Type.GetType("System.Int32")) 8End With 9 10With New StreamReader("test.txt", System.Text.Encoding.Default) 11 While .Peek() > -1 12 Dim value() As String = .ReadLine.Split(","c) 13 dtRow = mydb.NewRow() 14 dtRow("no") = no 15 dtRow("date") = value.ToArray(0) 16 dtRow("value") = value.ToArray(1) 17 mydb.Rows.Add(dtRow) 18 no = no + 1 19 End While 20End With

ちなみに、以下の処理だとめっちゃくちゃ時間がかかって話になりませんでした、、、

lang

1Dim TitleDate As String 2TitleDate = MyDB.Select("no=0").ToArray(0).Item("date") 3 4For i = 0 To 1440 5 dtRow = ds.Tables(0).NewRow 6 dtRow(0) = DateTime.Parse(TitleDate & " 00:00").AddMinutes(i).ToString("yyyy/MM/dd HH:mm") 7 dtRow(1) = MyDB.Compute("Avg(value)", "Convert(date, 'System.String') LIKE '" & dtRow(0).ToString & "%'") 8 ds.Tables(0).Rows.Add(dtRow) 9Next

すばやく1分毎の平均値を取得するにはどのように行えば良いでしょうか?
DataTableよりも高速な方法があれば、そちらも教えて頂きたいです。
よろしくご教示下さい。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

クエリ式を使われてはいかがでしょう。
クエリ式の構文例 : 集計演算子(MSDN)

当方VBの知識があまりないのでC#で申し訳ありませんがご参考になれば。

ちなみに、当方環境で集計処理は100ミリ秒程度でした。

lang

1static void Main(string[] args) 2{ 3 4 DataTable table = new DataTable(); 5 table.Columns.Add("id", typeof(int)); 6 table.Columns.Add("date", typeof(DateTime)); 7 table.Columns.Add("dateMin", typeof(string)); // グルーピングのため年月日時分までのフィールドを追加 8 table.Columns.Add("value", typeof(int)); 9 10 DataColumn[] keyColumns = new DataColumn[1]; 11 keyColumns[0] = table.Columns["id"]; 12 table.PrimaryKey = keyColumns; 13 14 15 // ダミーデータ作成 16 Random rand = new Random(); 17 DateTime dt = DateTime.ParseExact("2015/01/01", "yyyy/MM/dd", null); 18 DateTime endDt = DateTime.ParseExact("2015/01/02", "yyyy/MM/dd", null); 19 20 Console.WriteLine("Start: Create Source Table"); 21 22 int id = 0; 23 while (dt < endDt) 24 { 25 DataRow row = table.NewRow(); 26 row[0] = id++; 27 row[1] = dt; 28 row[2] = dt.ToString("yyyy/MM/dd HH:mm"); 29 row[3] = rand.Next(0, 9999); 30 31 table.Rows.Add(row); 32 33 dt = dt.AddSeconds(1); 34 } 35 36 Console.WriteLine("End : Create Source Table"); 37 38 39 // 集計結果保存のテーブル 40 DataTable avgTable = new DataTable(); 41 avgTable.Columns.Add("date", typeof(DateTime)); 42 avgTable.Columns.Add("avg", typeof(double)); 43 44 Console.WriteLine("Stert: Calc Average"); 45 46 Stopwatch sw = new Stopwatch(); 47 sw.Start(); 48 49 // クエリ式の作成 50 var query = 51 from row in table.AsEnumerable() 52 group row by row.Field<string>(2) into r // 分までのデータでグルーピング 53 select new 54 { 55 key = r.Key, 56 avg = r.Average(row => (int)row[3]) 57 }; 58 59 // とりあえず結果をテーブルに保存 60 foreach (var avgRow in query) 61 { 62 DataRow row = avgTable.NewRow(); 63 row[0] = avgRow.key; 64 row[1] = avgRow.avg; 65 66 avgTable.Rows.Add(row); 67 } 68 sw.Stop(); 69 70 Console.WriteLine("End : Calc Average"); 71 Console.WriteLine(string.Format("Spend Time : {0} [ms]", sw.ElapsedMilliseconds)); 72 73 74 Console.ReadKey(); 75 76}

投稿2015/07/14 13:23

wakuwaku

総合スコア386

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

inukujira

2015/07/15 01:34

この方法でできました!^^ どうもありがとうございました!
guest

0

たぶん期待されている答えでは無いと思いますが、思い至ったので、、、

目的が、時系列データからの集計演算なので、読み込みと同時に計算してしまうのはダメでしょうか?

集計用テーブルを用意するか読み込み先テーブルに1列余分を作っておくかして、データファイルから1行ずつ読み込む時、分替わりまでデータ値を積算して積算個数をカウントし、分が替わったタイミングにその分の平均を求めてテーブルに格納するような処理です
毎秒データが86400行確実に入っているなら、カウントの必要もなく割る60すればよいですが

データファイルの読み込み後に、そのデータに対して変更等が発生しないなら、合計や平均のような集計演算は入力と同時に計算してしまうのが効率よいように思います

「データの読み込み時に読み込み以外の処理はできません」というお話ならまったくダメですが・・・

あと、これはご質問と異なる部分のお話なのですが

時系列データの1分平均の考え方について

2015/07/13 00:01 の平均値
といったら
2015/07/13 00:00:01 から 00:01:00 までの平均(積算値を60で割った値)
というのが私の感覚です
(ですので、2015/07/13 00:00 の平均値を求めたい場合には前日データが必要になります)

記述されたコードでは
2015/07/13 00:00:00 から 00:00:59 までのAve平均

2015/07/13 00:00 の平均値
として記録されるような気がします

未来の値で平均を作るのはどうもしっくりきませんが・・・そこは問題ないでしょうか?

(データファイルの先頭が0秒なので、それを前日データとするのか、当日データとするのか・・・)
(最後は23:59で終わるのか、00:00で終わるのか・・・)
(余計なことですが気になったので)

投稿2015/07/14 07:41

takito

総合スコア3111

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問