<目的>関連したデータ同士をグループにまとめたい。

データベースの中の1つのデータを検索して、直接関係のあったデータを抽出してできたcsvファイルがあります。
現在、全てのデータに対してデータベース内検索して作った以下のような総当りデータがあります。
(No1のデータを検索したところ、No2,3,4のデータと関係があった。No2のデータを検索したところ、No1のデータと関係があった。・・・)
↓csvファイル------------
1,2,3,4
2,1
3,1,4
4,1,3,5
5,4
6,7
7,6
8
↑csvファイル-----------

ここで、直接的および間接的に関係のあるもの同士を1つのグループにまとめたいと考えています。
上の例では以下のような3つのグループにまとめられます。

1,2,3,4,5
6,7
8

このようにグループにまとめる処理をどのようにおこなったらよいでしょうか?
当方はPerlとExcelマクロであれば多少わかります。
ただし処理したい実際のcsvファイルは12万行あるのでExcelには収まりませんでした。
出来ればPerlのコードを書いていただけると非常に助かります。
よろしくお願いします。

回答の条件
  • 1人3回まで
  • 登録:2009/04/24 16:22:28
  • 終了:2009/04/27 13:54:11

ベストアンサー

id:jccrh1 No.1

jccrh1回答回数111ベストアンサー獲得回数192009/04/25 07:51:16

ポイント200pt

EXCEL VBAで作成しました。

関係したNOは番号が数字か分かりませんでしたので、連想配列で判別をしました。

→参照設定で「Microsoft Scripting Runtime」を追加してください。

CSV入出力ファイルのフォルダはEXCELファイルと同一フォルダーで処理するようにしました。

ファイル名は変更してください。

Option Explicit
Sub 集計処理()
  Const CSV_IN = "\関連データ.csv"
  Const CSV_OT = "\グループデータ.csv"
  Dim グループ判定           As New Scripting.Dictionary
  Dim 判定番号               As Long
  Dim 決定番号               As Long
  Dim グループCSV(120000)  As String
  Dim 関連データ             As String
  Dim 分解                   As Variant
  Dim I                   As Long

  Open ThisWorkbook.Path & CSV_IN For Input As #1
  Do While Not (EOF(1))
    Line Input #1, 関連データ
    分解 = Split(関連データ, ",")
    If グループ判定.Exists(分解(0)) Then                                ' グループにある場合
      決定番号 = グループ判定.item(分解(0))
     グループCSV(決定番号) = グループCSV(決定番号) & "," & 分解(0)
    Else                                                              ' グループにない場合
      判定番号 = 判定番号 + 1
   決定番号 = 判定番号
   グループ判定.Add (分解(0)), 決定番号
   グループCSV(決定番号) = 分解(0)
    End If
    For I = 1 To UBound(分解)
      If Not (グループ判定.Exists(分解(I))) Then
        グループ判定.Add (分解(I)), 決定番号
      End If
    Next I
  Loop
  Close
  
  Open ThisWorkbook.Path & CSV_OT For Output As #1
  For I = 1 To 判定番号
    Print #1, グループCSV(I)
  Next I
  Close
End Sub
id:cacataga

回答ありがとうございました!

回答をあけるのが遅くなってしまい申し訳ありませんでした。

さきほど数個のデータについて試してみたところ、うまく処理されていました。

VBAに関してはまだ勉強不足で書いてくださったコードの詳細についてはわからないところもありますが、これを良い教科書に勉強したいと思います。

2009/04/27 13:41:49

その他の回答(1件)

id:jccrh1 No.1

jccrh1回答回数111ベストアンサー獲得回数192009/04/25 07:51:16ここでベストアンサー

ポイント200pt

EXCEL VBAで作成しました。

関係したNOは番号が数字か分かりませんでしたので、連想配列で判別をしました。

→参照設定で「Microsoft Scripting Runtime」を追加してください。

CSV入出力ファイルのフォルダはEXCELファイルと同一フォルダーで処理するようにしました。

ファイル名は変更してください。

Option Explicit
Sub 集計処理()
  Const CSV_IN = "\関連データ.csv"
  Const CSV_OT = "\グループデータ.csv"
  Dim グループ判定           As New Scripting.Dictionary
  Dim 判定番号               As Long
  Dim 決定番号               As Long
  Dim グループCSV(120000)  As String
  Dim 関連データ             As String
  Dim 分解                   As Variant
  Dim I                   As Long

  Open ThisWorkbook.Path & CSV_IN For Input As #1
  Do While Not (EOF(1))
    Line Input #1, 関連データ
    分解 = Split(関連データ, ",")
    If グループ判定.Exists(分解(0)) Then                                ' グループにある場合
      決定番号 = グループ判定.item(分解(0))
     グループCSV(決定番号) = グループCSV(決定番号) & "," & 分解(0)
    Else                                                              ' グループにない場合
      判定番号 = 判定番号 + 1
   決定番号 = 判定番号
   グループ判定.Add (分解(0)), 決定番号
   グループCSV(決定番号) = 分解(0)
    End If
    For I = 1 To UBound(分解)
      If Not (グループ判定.Exists(分解(I))) Then
        グループ判定.Add (分解(I)), 決定番号
      End If
    Next I
  Loop
  Close
  
  Open ThisWorkbook.Path & CSV_OT For Output As #1
  For I = 1 To 判定番号
    Print #1, グループCSV(I)
  Next I
  Close
End Sub
id:cacataga

回答ありがとうございました!

回答をあけるのが遅くなってしまい申し訳ありませんでした。

さきほど数個のデータについて試してみたところ、うまく処理されていました。

VBAに関してはまだ勉強不足で書いてくださったコードの詳細についてはわからないところもありますが、これを良い教科書に勉強したいと思います。

2009/04/27 13:41:49
id:airplant No.2

airplant回答回数220ベストアンサー獲得回数492009/04/25 18:06:29

ポイント200pt

興味を惹かれたので、ExcelのVBAでテキストを読み込んでグループ化するマクロを作ってみました。シートにはデータを読み込んでいませんので、行数は12万行でも大丈夫です。試しに1万行を数字や英文でやってみましたが、数秒で終わるので12万行でもすぐに終わるものと思います。


Option Explicit

Sub GetRelationGroup()
        
    Const sInFile = "C:\temp\in.csv"
    Const sOutFile = "C:\temp\ans.csv"
    Dim sTextLine As String
    Dim sSplitBuf() As String
    Dim i As Long, j As Integer, lCnt As Long
    Dim bFind As Boolean
    Dim sNewKeys As String
    Dim vGroup() As Variant
    Dim sGroupWrk() As String
    
    Open sInFile For Input As #1
    lCnt = -1
    Do While Not EOF(1)
        Line Input #1, sTextLine
        sSplitBuf = Split(sTextLine, ",")
        '後ろのNull値は無効にする 1,2,,,,,→1,2
        For j = 0 To UBound(sSplitBuf)
            If sSplitBuf(j) = "" Then
                If j = 0 Then GoTo Continue
                ReDim Preserve sSplitBuf(j - 1) As String
                Exit For
            End If
        Next
        bFind = False
        For i = 0 To lCnt
            sNewKeys = ""
            For j = 0 To UBound(sSplitBuf)
                sGroupWrk = vGroup(i)
                If FindStr(sGroupWrk, sSplitBuf(j)) Then
                    bFind = True
                Else
                    'keyなし:追加する
                    sNewKeys = sNewKeys & "," & sSplitBuf(j)
                End If
            Next
            If bFind Then
                '関係分を追加
                vGroup(i) = Split(Join(vGroup(i), ",") & sNewKeys, ",")
                Exit For
            End If
        Next
        
        If Not bFind Then
            lCnt = lCnt + 1
            ReDim Preserve vGroup(lCnt) As Variant
            vGroup(lCnt) = sSplitBuf
        End If
Continue:
    Loop
    Close #1
    Open sOutFile For Output As #2
    For i = 0 To lCnt
        Print #2, Join(vGroup(i), ",")
    Next
    Close #2
    
End Sub


'Filter関数のマッチ版
Function FindStr(sSrcArray() As String, sFindStr As String) As Boolean

    Dim m As Integer
    
    FindStr = False
    For m = 0 To UBound(sSrcArray)
        If sSrcArray(m) = sFindStr Then
            FindStr = True
            Exit Function
        End If
    Next

End Function
id:cacataga

回答ありがとうございました!

回答をあけるのが遅くなってしまい申し訳ありませんでした。

わかりやすく色付けしたコードで書いてくださり、ご配慮に感謝です。

さきほど試しまして問題なく処理されているのを見て、VBA初心者の私から見たらただ敬服する次第です。

興味を持っていただいたようで参考までにお知らせしますが、処理するデータは遺伝子の塩基配列のデータから直接関係のある遺伝子同士を結びつけ、書いてくださったコードによって間接的に関連のある遺伝子をグループにまとめたということをしたかったのです。

おかげさまで解析を終えることが出来ました。

どうもありがとうございました!

2009/04/27 13:53:09
  • id:airplant
    嬉しいコメントありがとうございました。

    jccrh1さんのコードが短くて美しそうなので、どのように行っているのか、私が使ったデータで試してみました。
    その結果、ちょっとうまく出ていないようなので、実際に利用されるときは、気をつけてもらえるといいと思います。
    どうも、間接で関係しているデータがある場合、及び、同じキーが出てくると正しい結果になっていないようです。
    cacatagaさんのデータを動かした場合(1-8のデータ)は、同じように出ています。

    ●入力
    A1,A2,A3
    A1,A4
    B1,B2,B3
    A4,A10
    C2,C100
    B20,B1,B1,B2,B3,B4,B5,B6,B7,B8
    C20,C100
    C21,C101
    1,2,3,4
    2,1
    3,1,4
    4,1,3,5
    5,4
    6,7
    7,6
    8
    search,google,yahoo
    yahoo
    MS,C
    C,言語
    IE,google
    A1,A!!!!!!

    ●結果
    A1,A1,A4,A1
    B1
    C2
    B20
    C20
    C21
    1,2,3,4,5
    6,7
    8
    search,yahoo
    MS,C
    IE


    ●正しいと思われる結果
    A1,A2,A3,A4,A10,A!!!!!!
    B1,B2,B3,B20,B4,B5,B6,B7,B8
    C2,C100,C20
    C21,C101
    1,2,3,4,5
    6,7
    8
    search,google,yahoo,IE
    MS,C,言語

    P.S. 色は私がつけているわけではなく、はてな記法で自動でついています。
    >|vb|
     ここに書いたvb言語のキーワードが自動で色付きになる
    ||<
  • id:jccrh1
    airplantさん
    コメントありがとうございます。

    >データベースの中の1つのデータを検索して、直接関係のあったデータを抽出してできた…
    とのことで、最初のキーはユニークだと判断していました。
     
    よって
    A1,A2,A3
    A1,A4
     :
    と「A1」が複数回出現しないと考えておりました。
    注意書きをすれば良かったかと思います。
     
  • id:airplant
    jccrh1さんへ

    コメントありがとうございます。

    MS,C
    C,言語

    これは、ユニークなので、下記のようになると思いますが、、、
    MS,C,言語

    なぜか、「言語」が抜けてしまっています。
    MS,C

    下記と基本は同じかなと思うのですが。
    1,2,3,4
    2,1
  • id:jccrh1
    airplantさん
    いつもお世話なっています。

    これも、最初に説明したのとほぼ同じで最初のキーは「必ず存在する」と考えています。
    よって
     
    言語,C
      
    等があると思って作成しています。

    これからもよろしくお願いいたします。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません