Sorting words in a list of strings based on their relative frequencies, not regular sorting?
<p>Suppose I have a <code>pandas.Series</code> object:</p>

<pre><code>import pandas as pd

s = pd.Series(["hello there you would like to sort me", 
    "sorted i would like to be", "the banana does not taste like the orange", 
    "my friend said hello", "hello there amigo", "apple apple banana orange peach pear plum", 
    "orange is my favorite color"])
</code></pre>

<p>I want to sort the words inside each row based on the frequency with which each word occurs in the <em>entire</em> <code>Series</code>.</p>

<p>I can create a dictionary of the word: frequency key-value pairs easily:</p>

<pre><code>from collections import Counter

def create_word_freq_dict(series):
    return Counter(word for row in series for word in row.lower().split())

word_counts = create_word_freq_dict(s)
</code></pre>

<p>Without procedurally going through each row in the <code>Series</code>, how can I sort the word in this object by their relative frequencies? That is to say, for example, that "hello" occurs more frequently than "friend," and so should be further to the left in the resultant "sorted" string.</p>

<p>This is what I have:</p>

<pre><code>for row in s:
    ordered_words = []
    words = row.split()
    if len(words) == 1:
        ordered_words.append(words[0])
    else:
        i = 1
        prevWord = words[0]
        prevWord_freq = word_counts[prevWord]
        while i &lt; len(words):
            currWord = words[i]
            currWord_freq = word_counts[currWord]
            if currWord_freq &gt; prevWord_freq:
                prevWord = currWord
                prevWord_freq = currWord_freq
                words.append(currWord)
   ...
</code></pre>

<p>It's not complete yet, but is there a better way (as opposed to recursion) of sorting in this manner?</p>

<h1>Python 2</h1>

<p>All you have to do is create custom comparator based on your counter and call sorting</p>

<pre><code>s = ["hello there you would like to sort me", 
    "sorted i would like to be", "the banana does not taste like the orange", 
    "my friend said hello", "hello there amigo", "apple apple banana orange peach pear plum", 
    "orange is my favorite color"]


from collections import Counter

def create_word_freq_dict(series):
    return Counter(word for row in series for word in row.lower().split())

word_counts = create_word_freq_dict(s)

for row in s:
    print sorted(row.lower().split(), lambda x, y: word_counts[y] - word_counts[x])
</code></pre>

<p>So all I do here is simply call <code>sorted</code> with custom comparison operator, which ignores the word, and instead uses <code>word_counts</code> mapping to determine which one should be first.</p>

<p>and effect</p>

<pre><code>['hello', 'like', 'there', 'would', 'to', 'you', 'sort', 'me']
['like', 'would', 'to', 'sorted', 'i', 'be']
['like', 'orange', 'the', 'banana', 'the', 'does', 'not', 'taste']
['hello', 'my', 'friend', 'said']
['hello', 'there', 'amigo']
['orange', 'apple', 'apple', 'banana', 'peach', 'pear', 'plum']
['orange', 'my', 'is', 'favorite', 'color']
</code></pre>

<p>and to prove it really sorts according to frequencies:</p>

<pre><code>for row in s:
    sorted_row = sorted(row.split(), lambda x, y: word_counts[y] - word_counts[x])
    print zip(sorted_row, map(lambda x: word_counts[x], sorted_row))
</code></pre>

<p>produces</p>

<pre><code>[('hello', 3), ('like', 3), ('there', 2), ('would', 2), ('to', 2), ('you', 1), ('sort', 1), ('me', 1)]
[('like', 3), ('would', 2), ('to', 2), ('sorted', 1), ('i', 1), ('be', 1)]
[('like', 3), ('orange', 3), ('the', 2), ('banana', 2), ('the', 2), ('does', 1), ('not', 1), ('taste', 1)]
[('hello', 3), ('my', 2), ('friend', 1), ('said', 1)]
[('hello', 3), ('there', 2), ('amigo', 1)]
[('orange', 3), ('apple', 2), ('apple', 2), ('banana', 2), ('peach', 1), ('pear', 1), ('plum', 1)]
[('orange', 3), ('my', 2), ('is', 1), ('favorite', 1), ('color', 1)]
</code></pre>

<h2>Python 3</h2>

<p>In Python 3, <code>sorted</code> no longer accepts a function but <code>key</code> instead, thus you have to do conversion</p>

<pre><code>s = ["hello there you would like to sort me", 
    "sorted i would like to be", "the banana does not taste like the orange", 
    "my friend said hello", "hello there amigo", "apple apple banana orange peach pear plum", 
    "orange is my favorite color"]

from functools import cmp_to_key
from collections import Counter

def create_word_freq_dict(series):
    return Counter(word for row in series for word in row.lower().split())

word_counts = create_word_freq_dict(s)


for row in s:
    sorted_row = sorted(row.split(), key=cmp_to_key(lambda x, y: word_counts[y] - word_counts[x]))
    print(sorted_row)
</code></pre>

python sorting