Hans.Gundlach
Hans.Gundlach

Reputation: 431

how to divide a 2d list by last element haskell?

I am trying to group lists in a 2dlist based on the last element in each list in Haskell. Like this:

[[0,1],[2,2],[0,2],[1,1]]

would either become a 3d list like this:

[[[0,1],[1,1]],[[0,2],[2,2]]]

or would separate the data into n number of categories using any data structures.

Specifically, I'm trying to implement the seperateByClass Method in this tutorial http://machinelearningmastery.com/naive-bayes-classifier-scratch-python/

Upvotes: 0

Views: 164

Answers (2)

karakfa
karakfa

Reputation: 67507

import Data.List(groupBy, sortBy)
import Data.Ord(compare)

groupBy (\x y -> x!!1==y!!1) $ sortBy (\x y -> compare (x!!1) (y!!1)) [[0,1],[2,2],[0,2],[1,1]]
[[[0,1],[1,1]],[[2,2],[0,2]]]

or, change the indexed access to last

groupBy (\x y -> last x==last y) $ sortBy (\x y -> compare (last x) (last y)) [[0,1],[2,2],[0,2],[1,1]]
[[[0,1],[1,1]],[[2,2],[0,2]]]

perhaps easier with some helper functions

compareLast x y = compare (last x) (last y)
equalLast x y =  EQ == compareLast x y

groupBy equalLast $ sortBy compareLast [[0,1],[2,2],[0,2],[1,1]]
[[[0,1],[1,1]],[[2,2],[0,2]]]

Or, going one step further

compareBy f x y = compare (f x) (f y)
equalBy f = ((EQ ==) .) . compareBy f
partitionBy f = groupBy (equalBy f) . sortBy (compareBy f)

partitionBy last [[0,1],[2,2],[0,2],[1,1]]
[[[0,1],[1,1]],[[2,2],[0,2]]]

Upvotes: 1

hao
hao

Reputation: 10238

The goal is to convert

def separateByClass(dataset):
    separated = {}
    for i in range(len(dataset)):
        vector = dataset[i]
        if (vector[-1] not in separated):
            separated[vector[-1]] = []
        separated[vector[-1]].append(vector)
    return separated


dataset = [[1,20,1], [2,21,0], [3,22,1]]
separated = separateByClass(dataset)
print('Separated instances: {0}').format(separated)

which has output

Separated instances: {0: [[2, 21, 0]], 1: [[1, 20, 1], [3, 22, 1]]}

to Haskell. This is the perfect use-case for Data.Map's fromListWith :: Ord k => (a -> a -> a) -> [(k, a)] -> Map k a, which takes a list of key-value pairs and a strategy for combining values when two pairs happen to share the same key.

λ> import Data.Maybe
λ> import Data.Map
λ> let last_ = listToMaybe . reverse
λ> let pairs = [(last_ x, [x]) | x <- dataset]

λ> fromListWith (\a b -> b) pairs
fromList [(Just 0,[[2,21,0]]),(Just 1,[[1,20,1]])]

λ> fromListWith (++) pairs
fromList [(Just 0,[2,21,0]),(Just 1,[3,22,1,1,20,1])]

λ> fromListWith (++) pairs
fromList [(Just 0,[[2,21,0]]),(Just 1,[[3,22,1],[1,20,1]])]

Great job, Haskell.

Upvotes: 1

Related Questions