在Ruby中搜索单个词和组合词

在Ruby中搜索单个词和组合词,ruby,frequency,stop-words,Ruby,Frequency,Stop Words,我希望我的输出能够搜索和计算单词“candy”和“gram”的频率,以及给定文本(整个_文件)中“candy gram”和“gram candy”的组合 我目前正在使用以下代码来显示“candy”和“gram”的出现情况,但是当我在%w中聚合组合时,只显示“candy”和“gram”的单词和频率。我应该换一种方式吗?非常感谢 myArray = whole_file.split stop_words= %w{ candy gram 'candy gram' 'gram candy' } n

我希望我的输出能够搜索和计算单词“candy”和“gram”的频率,以及给定文本(整个_文件)中“candy gram”和“gram candy”的组合 我目前正在使用以下代码来显示“candy”和“gram”的出现情况,但是当我在%w中聚合组合时,只显示“candy”和“gram”的单词和频率。我应该换一种方式吗?非常感谢

myArray = whole_file.split

stop_words= %w{ candy gram 'candy gram' 'gram candy' } 

nonstop_words = myArray - stop_words

key_words = myArray - nonstop_words

frequency = Hash.new (0)

key_words.each { |word| frequency[word] +=1 }

key_words = frequency.sort_by {|x,y| x }

key_words.each { |word, frequency| puts word + ' ' + frequency.to_s }

听起来你在找我。您可以首先将文本分解为连续单词的组合,然后计算结果单词分组数组中的出现次数。下面是一个例子:

whole_file = "The big fat man loves a candy gram but each gram of candy isn't necessarily gram candy"

[["candy"], ["gram"], ["candy", "gram"], ["gram", "candy"]].each do |term|
  terms = whole_file.split(/\s+/).each_cons(term.length).to_a
  puts "#{term.join(" ")} #{terms.count(term)}"
end
编辑:正如下面的评论所指出的,我没有给予足够的关注,而是在每个循环中分割文件,这显然不是一个好主意,尤其是如果文件很大的话。我也没有解释原始问题可能需要按计数排序的事实,尽管没有明确要求

whole_file = "The big fat man loves a candy gram but each gram of candy isn't necessarily gram candy"
# This is simplistic. You would need to address punctuation and other characters before
# or at this step.
split_file = whole_file.split(/\s+/)
terms_to_count = [["candy"], ["gram"], ["candy", "gram"], ["gram", "candy"]]
counts = []

terms_to_count.each do |term|
  terms = split_file.each_cons(term.length).to_a
  counts << [term.join(" "), terms.count(term)]
end

# Seemed like you may need to do sorting too, so here that is:
sorted = counts.sort { |a, b| b[1] <=> a[1] }
sorted.each do |count|
  puts "#{count[0]} #{count[1]}"
end
whole\u file=“大胖子喜欢一克糖果,但每克糖果不一定都是克糖果”
#这太简单了。您需要先解决标点符号和其他字符
#或者在这一步。
拆分文件=整个文件。拆分(/\s+/)
术语对计数=[“糖果”]、[“克”]、[“糖果”、“克”]、[“克”、“糖果”]]
计数=[]
每一项都可以计算|
terms=拆分文件。每个文件都包含(term.length)。到

计数标点符号并转换为小写

您可能要做的第一件事是删除包含文件内容的字符串中的所有标点符号,然后将剩下的内容转换为小写,这样您就不用担心将“Cat”和“Cat”计算为同一个单词。这两个操作可以按任意顺序进行

将大写字母更改为小写字母很容易:

text = whole_file.downcase
要删除标点符号,可能更容易决定保留什么而不是丢弃什么。如果我们只想保留小写字母,您可以这样做:

text = whole_file.downcase.gsub(/[^a-z]/, '')
也就是说,用空字符串替换除(
^
)小写字母以外的所有字符。1

确定单个单词的频率

如果要计算
text
包含单词
'candy'
的次数,可以使用字符串
text
上的方法,然后确定返回的数组的大小:

text.scan(/\bcandy\b/).size
scan
返回一个数组,其中包含字符串的每次出现
'candy'
.size
返回该数组的大小。这里
\b
确保
'candy gram'
在每一端都有一个单词“boundary”,可以是空格,也可以是行或文件的开头或结尾。这是为了防止“烛台”被计算在内

第二种方法是将字符串
文本
转换为单词数组,如您所做的2:

如果你不介意的话,我想称之为:

words = text.split
因为我觉得这更有表现力

确定“糖果”出现次数的最直接方法是使用以下方法:

words.count('candy')
您还可以使用数组差分方法,如您所述:

words.size - (words - ['candy']).size
如果您想知道“candy”或“gram”出现的次数,您当然可以对每一次进行上述操作,并将两次计数相加。其他方法包括:

words.size - (myArray - ['candy', 'gram']).size
words.count { |word| word == 'candy' || word = 'gram' }
words.count { |word| ['candy', 'gram'].include?(word) }
确定文本中出现的所有单词的频率

使用默认值为零的哈希是一个不错的选择:

def frequency_of_all_words(words)
  frequency = Hash.new(0)
  words.each { |word| frequency[word] +=1 }
  frequency
end
我写这篇文章是为了强调
单词。每个…
都不会返回
频率。通常,您会看到使用返回散列(“对象”)的方法更简洁地编写此文件:

一旦你有了散列
频率
,你就可以像以前那样对它进行排序:

frequency.sort_by {|word, freq| freq }

你可以这样写:

frequency.sort_by {|_, freq| freq }
因为您没有使用第一个块变量。如果您首先想要最常用的单词:

frequency.sort_by(&:last).reverse

所有这些都将为您提供一个数组。如果要将其转换回散列(例如,先使用最大值):

或者在Ruby 2.0+中

frequency.sort_by(&:last).reverse.to_h
计算子字符串出现的次数

现在让我们计算字符串
'candy gram'
出现的次数。您可能认为我们可以对保存整个文件的字符串使用
String#scan
,就像我们前面所做的那样4:

第一个问题是,这不会捕获“candy\ngram”;i、 例如,当单词由换行符分隔时。我们可以通过将正则表达式更改为
/\bcandy\sgram\b/
来解决这个问题。第二个问题是“糖果克”可能是“糖果”。Gram'在文件中,在这种情况下,您可能不想计算它

更好的方法是在数组
words
上使用该方法。向您展示其工作原理的最简单方法是通过示例:

words = %w{ check for candy gram here candy gram again }
  #=> ["check", "for", "candy", "gram", "here", "candy", "gram", "again"]
enum = words.each_cons(2)
  #=> #<Enumerator: ["check", "for", "candy", "gram", "here", "candy",
  #                  "gram", "again"]:each_cons(2)>
enum.to_a
  #=> [["check", "for"], ["for",  "candy"], ["candy", "gram"],
  #    ["gram", "here"], ["here", "candy"], ["candy", "gram"],
  #    ["gram", "again"]]
最后:

words.each_cons(2).map { |word_pair|
  word_pair.join(' ') }.count { |s| s == 'candy gram' }
  #=> 2
1如果还希望保留破折号,对于连字符的单词,请将正则表达式更改为
/[^-a-z]/
/[^a-z-]/

2注意,
.split
.split(“”)
.split(/\s+/)
相同


3此外,Ruby的命名约定是对变量和方法使用小写字母和下划线(“蛇壳”),例如
my_array

我将尝试@dnunez24!还有,我注意到你来自玫瑰之城!那是我的家乡!另外,我尝试了一下,得到了一个空输出:/是的,对不起。我没有编写完整的程序来输出您需要的字符串。您需要获取我在示例中显示的计数结果,并将其转换为所需的输出。我不是波特兰人,但已经在这里呆了几年了,我很喜欢这里。:)@dnunez24-您可能希望
在循环之外拆分
。谢谢,@urigassi。我以前确实做过,但编辑过我的帖子。抢手货我将再次修改它。我不理解,“…显示计数次数的文本”可以
frequency.sort_by {|_, freq| -freq }
Hash[frequency.sort_by(&:last).reverse]
frequency.sort_by(&:last).reverse.to_h
text.scan(/\bcandy gram\b/).size
words = %w{ check for candy gram here candy gram again }
  #=> ["check", "for", "candy", "gram", "here", "candy", "gram", "again"]
enum = words.each_cons(2)
  #=> #<Enumerator: ["check", "for", "candy", "gram", "here", "candy",
  #                  "gram", "again"]:each_cons(2)>
enum.to_a
  #=> [["check", "for"], ["for",  "candy"], ["candy", "gram"],
  #    ["gram", "here"], ["here", "candy"], ["candy", "gram"],
  #    ["gram", "again"]]
words.each_cons(2).map { |word_pair| word_pair.join(' ') }
  #=> ["check for", "for candy", "candy gram", "gram here",
  #    "here candy", "candy gram", "gram again"]
words.each_cons(2).map { |word_pair|
  word_pair.join(' ') }.count { |s| s == 'candy gram' }
  #=> 2