アプリ版:「スタンプのみでお礼する」機能のリリースについて

●処理元データCSVファイル:約30万件
1)列項目名は3行目にあり1~2行目データはメモ項目で全列数80~85列に対して5~9列で一定になっていません。
2)列項目は時期に応じ若干の差があり3タイプに分類。
3)分析に使用するデータは全行約600行の内4~5行目のデータのみ。
■分析前処理
1)処理元データを列項目別に4~5行目のデータを集計する。
●分析
 過去経験で対応可能。

 マクロ記録「外部データ取込」を利用してその他の処理を加えデータのまとめ分析作業自動化をと考えています。
 ■分析前処理に関し、CSVを1件ずつ呼出た上で分析に必要な行を切出・・・・と過去経験での処理も可能とは考えていますが、従来アウトプットに迫られ勉強が出来ていない配列やCSVデータの直接処理を使い処理時間を短縮できないものかと考えています。

上記CSVファイルからの指定行3~5行目のデータ取得に関しご教授をお願いします。

A 回答 (6件)

私も、一言・二言・三言。


なぜ、アップロードを早めたかからですが、このまま頭の中だけに入れておくと忘れてしまうからです。

#5さんのご指摘のことは、一応は織り込み済みですが、
どこかでエラーが出たら、続きができるようにした方がよいでしょうね。
そのために、先にファイル名を取得しました。

途中で休むようにすればよいものですが、プロシージャ外にしても、エラートラップに引っかかれば、その記録は残せます。ただし、全体的なエラーを出せば、myArray の中身自体も飛んでしまいます。


 '//
そのために、こんなところに切れ目を入れたのです。


本来は、
Sub CSVImportPro()
 Dim myArray

ではなく、

Private myArray
Sub CSVImportPro()

です。
Dimの宣言の下あたりに、On Error Goto ErrHandler
の一行を加えます。

当然、ルールの一番出し入れの大きい部分に、
DoEvents
は入れておいたほうが安全です。

それとこの部分です。失敗したら、その次の番号を下記に入れます。
 For i = LBound(myArray) To UBound(myArray)
  ↓
 For i = (リテラルな数字) To UBound(myArray)

On Error GoTo  ErrHandler

Exit Sub
ErrHandler:
 Debug.Pring i; myArray(i)

End Sub
としたら、良いかと考えています。
    • good
    • 0
この回答へのお礼

自分の力ではまだ付いていけませんが
nicotinismさん WindFallerさん
論議ありがとうございました。

再度質問をさせて頂くかもしれませんがよろしくお願いします。
ベストアンサーは保留とさせてください。

お礼日時:2016/07/08 12:12

軽く


>Dir関数などで30万回呼び出すとか・・・
と言ってしまいましたが、
30万個もあると何処かでエラーになって止まるかも知れない。
例えばですが、コマンドプロンプトで、Dir e:\tmp /s /b > check.txt 等々で
書き出してこれをシートに取り込み、対象ファイルのリストを作成。
一個処理が終わるごとに隣のセルに1。
途中から再開する場合にやりやすい・エラーファイルが分かりやすい「かも」?

ループ処理中にカウンタを入れて
if i mod 100 = 0 then
beep
do events とかにすると途中で止めやすく「応答なし」が避けられます。
beep 五月蠅いから却下?

取得自体は出来たとして、
出力をどのようにするかは、今のところ保留です。

恥ずかしながら30万件のファイルの一括処理は未経験ですので
興味津々です。(なかば野次馬根性?です。すみません。)
    • good
    • 0
この回答へのお礼

自分の力ではまだ付いていけませんが
nicotinismさん WindFallerさん
論議ありがとうございました。

再度質問をさせて頂くかもしれませんがよろしくお願いします。
ベストアンサーは保留とさせてください。

お礼日時:2016/07/08 12:12

この時期にアップロードしないほうがよかったかもしれません。



Excelのシートへ出力のタイミングをどこでするかによって変わるような気がします。それ以外は、どうあがいても、まともな作り方をすれば、#3さんのものと大きく変わるわけではありませんが、それを、あえて別な方法にしてしまいました。

Dir のファイル名データを、最初配列の中で蓄えてから処理するという方法から、すべて配列の中で処理していく方法は、私のやり方にしても、その後のテキストインポートを、FileSystemObject を使ってしまいました。

以下の最大の問題点は、コードが読みにくいということでしょうね。


'//
Sub CSVImportPro()
 Dim myArray
 Dim FName As String, myPath As String
 Dim objFS As Object
 Dim objText As Object
 Dim i As Long
 Dim Culs, arCul
 
 '出力の項目
 Culs = "2,3,5,6"

 myPath = "C:\Temp\Test1\" '末尾は"\"
 
 ReDim myArray(400000)
 Set objFS = CreateObject("Scripting.FilesystemObject")
 FName = Dir(myPath & "*.csv", vbNormal)
 Do While FName <> ""
   If FName <> "." And FName <> ".." Then
    If (GetAttr(myPath & FName) And vbNormal) = vbNormal Then
      'If FileLen(myPath & FName) > 10 Then ' ファイルサイズ
        myArray(i) = FName
        i = i + 1
      'End If
    End If
   End If
   FName = Dir
 Loop
 If i = 0 Then
   MsgBox "データが見つかりませんでした。", vbExclamation
   Exit Sub
 End If
 
 '//
 ReDim buf(3)  '4個まで
 Dim arBuf(4)  '5個まで
 Dim k As Long, j As Long, v
 Dim n As Long, l As Long, m As Long
 Dim buf1 As Variant
 k = 1
 For i = LBound(myArray) To UBound(myArray)
 If myArray(i) = "" Then Exit For
   Set objText = objFS.OpenTextFile(myPath & myArray(i))
   n = 0
   For j = 1 To 5     '1行目から5行目まで
   If objText.AtEndofStream = True Then Exit For
     If j > 2 Then
       arBuf(n) = objText.ReadLine
       n = n + 1
     Else
       objText.SkipLine
     End If
   Next
   objText.Close
   For n = LBound(arBuf) To UBound(arBuf)
     buf1 = Split(arBuf(n), ",")
    m = UBound(buf1)
    If m > -1 Then
      k = k + 1
      '列の項目別
      'Cells(k, 1).Resize(, m + 1).Value = Buf1 '全部
      arCul = Split(Culs, ",")
      l = 0
      For Each v In arCul
        If UBound(buf1) >= v - 1 Then
          Cells(k, 1 + l).Value = buf1(v - 1)
        l = l + 1
        End If
      Next v
    End If
   Next n
   Erase arBuf
 Next i
End Sub
    • good
    • 0
この回答へのお礼

ありがとうございました

現在出張中で動作確認できませんが、来週帰社したらダミーファイルで早速ステップ動作を確認しながら本件に合わせ修正を加えてなんとかやってみるつもりですが・・・

関連部署との打合せでやはり結果を急かされてしまい、システム部にロギングデータサブファイルの再細分化を依頼しました、今回は「力づく」で「おまじない【doevent】連発」処理しながら、サブファイルリスト作成⇒ファイルリスト作成⇒全体呼出/必要行切出⇒分析集計・・・・となってしまいそうですが、

自分のレベルアップも含め「力づく」からの脱却を目指します。
その際自分の力不足もあり再度質問をさせて頂くかもしれませんがよろしくお願いします。

お礼日時:2016/07/08 12:12

こんな関数を作成して、Dir関数などで30万回呼び出すとか・・・


確認用にイミディエイトウィンドウに出力しています。
例:mygetrows("ファイルのフルパス",2,5,7) で2・5・7項目めを選択
3~5行目を取り出しています。

Function myGetRows(ByVal myFilePath As String, _
          ParamArray cAry() As Variant) As String
  Dim FF As Integer
  Dim i As Integer, j As Integer
  Dim v As Variant, vr As Variant

  FF = FreeFile
  Open myFilePath For Input As #FF
  Do Until EOF(FF)
    i = i + 1
    Line Input #FF, v
    
    If i > 2 Then 'データの始まり
      vr = Split(v, ",")
      myGetRows = myGetRows & v & vbCrLf '取りあえず全項目 (^_^;))
      'Debug.Print v
      For j = LBound(cAry) To UBound(cAry)
      '最左項目を1として指定した項目だけ取り出したい時の参考に
        Debug.Print , j, vr(cAry(j) - 1)
      Next
    End If
    
    If i > 4 Then '
      myGetRows = Left(myGetRows, Len(myGetRows) - 2) '最後の改行削除
      Close FF
      Exit Do
    End If
    
  Loop
End Function

そのCSVファイルの文字コード次第ではご破算かも、
変なところに余計なカンマがあると×無くても。。。
投稿用にタブインデントを全角スペースに変換しています。
ご参考まで。
    • good
    • 0
この回答へのお礼

ありがとうございました

現在出張中で動作確認できませんが、来週帰社したらダミーファイルで早速ステップ動作を確認しながら本件に合わせ修正を加えてなんとかやってみるつもりです。
自分の力不足もあり再度質問をさせて頂くかもしれませんがよろしくお願いします。

追記
CSVファイルの文字コードの件は、エクセル「外部データ取込」で問題ないことは確認できています。

お礼日時:2016/07/06 13:10

こんばんは



外注も検討してみてはいかがでしょうか?

WindFallerさんのアドバイスにもありますように、情報不足で回答やサポートは出来ません。
業者さんを探して、外注することも検討してみてください。
    • good
    • 0
この回答へのお礼

ありがとうございました。

言葉が足りなく情報が不足してしまいました。
WindFallerさんへのお礼を参照してください。

本件予算の関係もありここは内製でがんばってみるつもりです。

お礼日時:2016/07/06 13:10

こんばんは。



とても興味を持ちました。
私の乏しい経験からすると、オーソドックスな方法が一番のような気がします。
しかし、VBAマクロとして読むと、具体性がない点がいくつかあります。

人によっては、このまま作ってしまうことが可能だと思いますが、

・処理元データを列項目別に4~5行目のデータを集計する。(集計とは合計の計算と考えます)

・CSVファイルからの指定行3~5行目のデータ取得に
つまり項目名を含むというとこです。

ここら辺で、ちょっとどちらだろうか、どうするのだろうか、そもそもファイルの一部のデータを取り出すということで、そのデータ名などは、どこかに必要なのかなとか、そして、結果としては、30万ファイルなら、60~90万行になるということです。それでは、管理もできないだろうなとかなど。

とりとめもなくいろんな疑問が湧いてきてしまいます。

どのようなスタイルにするか、ひな形でもあるとよいのですが。
    • good
    • 0
この回答へのお礼

ありがとうございました。

以下言葉が足りませんでした。
集計:4行目5行目データを切り出し項目タイプ別に行を追加していく事です、データ処理系で何と呼ぶのか知識が無くやむなく「集計」としました。
3~5行目:項目タイプ別に振り分けるため項目行を含めています。
データ名:項目の中に年月日時分秒の情報製品SNが含まれているため後の分析につなげる事が可能です。
データの用途他:対象は設備管理用にロギングしているデータです、本来は項目ごとに集計/バッチ分析している物で事足りるはずでしたが・・・・、事情があり生データからの再分析が必要になってしまいました。


『このまま・・・可能だと思いますが』に関し
従来手法「呼出⇒切出⇒「集計」⇒分割保存」でデータ量/処理量かなり重くなり「おまじない【doevent】連発」になりそうですが、分割保存まで行けばなんとかなるとの感触は持っています。
今回自分の勉強/レベルアップを含めてもう少しスマートに出来ないかと質問をさせて頂いた次第です。

お礼日時:2016/07/06 13:21

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!