Sorting 查找最频繁项的最有效数据结构
我想从中提取最频繁的单词,它的未压缩形式大约为20GB。我不想使用整个数据集,只想使用其中最频繁的5000个。但是如果我写Sorting 查找最频繁项的最有效数据结构,sorting,haskell,data-structures,word-frequency,Sorting,Haskell,Data Structures,Word Frequency,我想从中提取最频繁的单词,它的未压缩形式大约为20GB。我不想使用整个数据集,只想使用其中最频繁的5000个。但是如果我写 take 5000 $ sortBy (flip $ comparing snd) dataset -- dataset :: IO [(word::String, frequency::Int)] 这将是无休止的等待。但是我应该怎么做呢 我知道有一个包可用于就地数组计算,但我在其文档页面上看不到任何项修改函数。也有,但它是一个无序的数据结构 我想使用simple(使用它
take 5000 $ sortBy (flip $ comparing snd) dataset
-- dataset :: IO [(word::String, frequency::Int)]
这将是无休止的等待。但是我应该怎么做呢
我知道有一个包可用于就地数组计算,但我在其文档页面上看不到任何项修改函数。也有,但它是一个无序的数据结构
我想使用simple(使用它方便的lookupLE
函数),但我不认为它会非常有效,因为它会在每次修改时生成一个新的映射。ST
monad能改善这一点吗
UPD:我还将程序的最终版本发布在了上 怎么样
- 使用
将数据集划分为前5000个项目和其余项目splitAt
- 按频率对前5000项进行排序(升序)
- 过完剩下的
- 如果某个项目的频率高于排序项目中的最低频率
- 从已排序的项目中删除频率最低的项目
- 将新项目插入已排序项目的适当位置
导入数据列表(foldl')
导入数据。可能(fromJust)
导入数据。堆隐藏(拆分)
mostFreq::Int->[(字符串,Int)]->[(字符串,Int)]
mostFreq n数据集=最终
哪里
--将配对从(String,Int)更改为(Int,String)
pairs=映射交换数据集
--在一个列表中获取第一个'n'对,在另一个列表中获取其余的对
(第一,rest)=在n对处拆分
--将所有前'n'对放入一个碎纸堆中
start=fromList first::MinHeap(Int,String)
--然后跑完剩下的几对
停止=折叠“步进-开始-休息”
--修改堆以替换其最不频繁的堆对
--如果新配对更频繁,则使用新配对
步骤堆对=如果视图头堆<仅对
然后插入对(来自$viewTail堆)
其他堆
--将(Int,String)对的堆转换为(String,Int)对的列表
最终=地图交换(toList停止)
交换~(a,b)=(b,a)
怎么样
- 使用
将数据集划分为前5000个项目和其余项目splitAt
- 按频率对前5000项进行排序(升序)
- 过完剩下的
- 如果某个项目的频率高于排序项目中的最低频率
- 从已排序的项目中删除频率最低的项目
- 将新项目插入已排序项目的适当位置
导入数据列表(foldl')
导入数据。可能(fromJust)
导入数据。堆隐藏(拆分)
mostFreq::Int->[(字符串,Int)]->[(字符串,Int)]
mostFreq n数据集=最终
哪里
--将配对从(String,Int)更改为(Int,String)
pairs=映射交换数据集
--在一个列表中获取第一个'n'对,在另一个列表中获取其余的对
(第一,rest)=在n对处拆分
--将所有前'n'对放入一个碎纸堆中
start=fromList first::MinHeap(Int,String)
--然后跑完剩下的几对
停止=折叠“步进-开始-休息”
--修改堆以替换其最不频繁的堆对
--如果新配对更频繁,则使用新配对
步骤堆对=如果视图头堆<仅对
然后插入对(来自$viewTail堆)
其他堆
--将(Int,String)对的堆转换为(String,Int)对的列表
最终=地图交换(toList停止)
交换~(a,b)=(b,a)
您是否尝试过这一点,或者您只是在猜测?因为许多Haskell排序函数都尊重惰性,当您只要求前5000个时,它们会很高兴地避免对其余元素进行排序
同样,要非常小心“每次变更都会生成一张新地图”。在这种数据结构上,大多数插入操作都将是O(logn),n限制在5000以内:因此,每次更改时,您可能会在堆中分配约30个新单元,但这并不是一个特别大的成本,当然不会像5000那么大
如果Data.List.sort
不够好,您需要的是:
import Data.List (foldl')
import Data.IntMap.Strict (IntMap)
import qualified Data.IntMap.Strict as IM
type Freq = Int
type Count = Int
data Summarizer x = Summ {tracking :: !IntMap [x], least :: !Freq,
size :: !Count, size_of_least :: !Count }
inserting :: x -> Maybe [x] -> Maybe [x]
inserting x Nothing = Just [x]
inserting x (Just xs) = Just (x:xs)
sizeLimit :: Summarizer x -> Summarizer x
sizeLimit skip@(Summ strs f_l tot lst)
| tot - lst < 5000 = skip
| otherwise = Summ strs' f_l' tot' lst'
where (discarded, strs') = IM.deleteFindMin strs
(f_l', new_least) = IM.findMin dps'
tot' = tot - length discarded
lst' = length new_least
addEl :: (x, Freq) -> Summarizer x -> Summarizer x
addEl (str, f) skip@(Summ strs f_l tot lst)
| i < f_l && tot >= 5000 = skip
| otherwise = sizeLimit $ Summ strs' f_l' tot' lst'
where strs' = IM.alter (inserting str) f strs
tot' = tot + 1
f_l' = min f_l f
lst' = case compare f_l f of LT -> lst; EQ -> lst + 1; GT -> 1
导入数据列表(foldl')
导入Data.IntMap.Strict(IntMap)
导入符合条件的Data.IntMap.Strict作为IM
类型Freq=Int
类型计数=Int
数据摘要器x=sum{tracking::!IntMap[x],least::!Freq,
大小::!计数,最小值的大小::!计数}
插入::x->Maybe[x]->Maybe[x]
插入x Nothing=Just[x]
插入x(仅xs)=仅(x:xs)
sizeLimit::摘要器x->摘要器x
sizeLimit skip@(总和)
|tot-lst<5000=跳过
|否则=汇总表'f_l'tot'lst'
其中(已丢弃,strs')=IM.deleteFindMin strs
(f_l',至少新)=IM.findMin dps'
tot'=tot-丢弃的长度
lst'=最小新长度
addEl::(x,Freq)->摘要器x->摘要器x
加法(str,f)跳过@(总和)
|i=5000=跳过
|否则=大小限制$Summ strs'f_l'tot'lst'
其中strs'=IM.alter(插入str)f strs
tot'=tot+1
f_l'=最小f_l f
lst'=LT->lst的案例比较f_l f;等式->lst+1;燃气轮机->1
注意,我们存储字符串列表以处理重复频率;我们通常跳过更新,一个
import Data.List (foldl')
import Data.IntMap.Strict (IntMap)
import qualified Data.IntMap.Strict as IM
type Freq = Int
type Count = Int
data Summarizer x = Summ {tracking :: !IntMap [x], least :: !Freq,
size :: !Count, size_of_least :: !Count }
inserting :: x -> Maybe [x] -> Maybe [x]
inserting x Nothing = Just [x]
inserting x (Just xs) = Just (x:xs)
sizeLimit :: Summarizer x -> Summarizer x
sizeLimit skip@(Summ strs f_l tot lst)
| tot - lst < 5000 = skip
| otherwise = Summ strs' f_l' tot' lst'
where (discarded, strs') = IM.deleteFindMin strs
(f_l', new_least) = IM.findMin dps'
tot' = tot - length discarded
lst' = length new_least
addEl :: (x, Freq) -> Summarizer x -> Summarizer x
addEl (str, f) skip@(Summ strs f_l tot lst)
| i < f_l && tot >= 5000 = skip
| otherwise = sizeLimit $ Summ strs' f_l' tot' lst'
where strs' = IM.alter (inserting str) f strs
tot' = tot + 1
f_l' = min f_l f
lst' = case compare f_l f of LT -> lst; EQ -> lst + 1; GT -> 1