
[code]

    ID_1 1
    ID_2 3
    ID_2 5
    ID_2 1
    ID_3 2
    ID_3 3
    …
    
[/code]

* * *
[code]

    ID_1 1
    ID_2 1 3 5
    ID_3 2 3
    …
    
[/code]

上記のような重複IDのあるデータセットから、重複のあったものを横結合するにはどうすればよいでしょうか？  
重複したIDを1行にし、昇順で並べたいと思っています。  
重複を削除する方法は多く見つかりますが、結合する方法は見つからずどう処理すればいいのか悩んでいます。  
よろしくお願いします。


CC BY-SA 3.0
2017-10-05T02:53:52.223
38447
2017-10-15T04:06:50.713
2017-10-05T05:36:26.503
19110
22885
question
python r
重複したIDの要素を結合する方法


具体的なデータの形式が分からないので抽象的な話になりますが、例えばPythonでリストの辞書を使って次のように書くのはどうでしょうか。

[code]

    data = [(1,1),(2,3),(2,5),(2,1),(3,2),(3,3)]
    
    id_dict = {}
    
    for d in data:
        id_dict.setdefault(d[0],[]).append(d[1])
    
    for i, l in id_dict.items():
        print(i, " : ", sorted(l))
    
[/code]

実行結果

[code]

    1  :  [1]
    2  :  [1, 3, 5]
    3  :  [2, 3]
    
[/code]

昇順で並べるのに`print`するところで整列しています。

IDの値の範囲が分からないので辞書を使っていますが、範囲が分かっていて（かつそれが小さいなら）リストのリストを使うことも考えられます。


CC BY-SA 3.0
2017-10-05T03:57:41.143
38454
2017-10-05T03:57:41.143
13199
38447
answer


データ形式が指定されていないのですが、

**pandas** であれば、`groupby()` を使って簡単に記述できます。

[code]

    import pandas as pd
    
    df = pd.DataFrame({
        'id':['ID_1','ID_2','ID_2','ID_2','ID_3','ID_3'],
        'value':[1,3,5,1,2,3]})
    
    result = df.groupby('id')['value'].apply(list)
    
[/code]


CC BY-SA 3.0
2017-10-05T04:43:41.860
38455
2017-10-05T04:43:41.860
24801
38447
answer


Rの場合  
tapplyで重複するIDごとのリストを作り、lapplyで好きな関数をあてれば、並び替えも簡単。

x <\- tapply(c(1, 3, 5, 1, 2, 3), c('ID_1', 'ID_2', 'ID_2', 'ID_2', 'ID_3',
'ID_3'), list)

lapply(x, sort)


CC BY-SA 3.0
2017-10-05T14:44:07.930
38469
2017-10-05T14:49:43.487
2017-10-05T14:49:43.487
25654
25654
38447
answer


`itertools.groupby` を使った方法もあります。  
`out` に並び順を保持するため `OrderedDict` を使ってますが並び順が不要であれば辞書でOKです。  
`data` はキーになる項目でソートされている必要があります。

<https://docs.python.jp/3/library/itertools.html#itertools.groupby>

[code]

    >>> from itertools import groupby
    >>> from collections import OrderedDict
    >>>
    >>> data = [
    ...     ("ID_1", 1),
    ...     ("ID_2", 3),
    ...     ("ID_2", 5),
    ...     ("ID_2", 1),
    ...     ("ID_3", 2),
    ...     ("ID_3", 3),
    ... ]
    >>> data
    [('ID_1', 1), ('ID_2', 3), ('ID_2', 5), ('ID_2', 1), ('ID_3', 2), ('ID_3', 3)]
    >>> out = OrderedDict()
    >>> for k, g in groupby(data, key=lambda v: v[0]):
    ...     value = [v[1] for v in g]
    ...     out[k] = sorted(value)
    ...
    >>> out
    OrderedDict([('ID_1', [1]), ('ID_2', [1, 3, 5]), ('ID_3', [2, 3])])
    >>> dict(out)
    {'ID_1': [1], 'ID_2': [1, 3, 5], 'ID_3': [2, 3]}
    
[/code]


CC BY-SA 3.0
2017-10-05T15:03:12.860
38471
2017-10-05T15:03:12.860
5375
38447
answer


Rでは`dplyr`, `tidyr`パッケージを使うのも良い方法だと思います．

[code]

    library(dplyr)
    library(tidyr)
    
    df = data.frame(
      id = c('ID_1', 'ID_2', 'ID_2', 'ID_2', 'ID_3', 'ID_3'),
      x  = c(1, 3, 5, 1, 2, 3)
    )
    
    df_spread = df %>%
      arrange(id, x) %>% 
      group_by(id) %>% 
      mutate(no = row_number()) %>%
      spread(key = no, value = x, sep ='_')
    
    print(df_spread)
    #> # A tibble: 3 x 4
    #> # Groups:   id [3]
    #>       id  no_1  no_2  no_3
    #> * <fctr> <dbl> <dbl> <dbl>
    #> 1   ID_1     1    NA    NA
    #> 2   ID_2     1     3     5
    #> 3   ID_3     2     3    NA
    
[/code]


CC BY-SA 3.0
2017-10-15T04:06:50.713
38709
2017-10-15T04:06:50.713
14668
38447
answer