Count values in a dict of lists and join keys and values names for the output using pandas

Viewed 114

I need help getting some outputs from a dictionary (python3):

{'horse': ['brown', 'black'], 'duck': ['brown', 'black', 'brown', 'grey', 'brown']}

Outputs required:

black horse: 1
brown horse: 1
grey horse: 0
black duck: 1
brown duck: 3
grey duck: 1

Can someone offer a solution please?

5 Answers

If you are looking to do this in just Python:

You can use Counter from collections module:

In [622]: from collections import Counter
In [623]: d = {'horse': ['brown', 'black'], 'duck': ['brown', 'black', 'brown', 'grey', 'brown']} 

In [611]: l = [j + ' ' + key for key, value in d.items() for j in value]

In [620]: Counter(l)                   
Out[620]: 
Counter({'brown horse': 1,
     'black horse': 1,
     'brown duck': 3,
     'black duck': 1,
     'grey duck': 1})

I guess this can be optimised further but you can try:

d={'horse': ['brown', 'black'], 'duck': ['brown', 'black', 'brown', 'grey', 'brown']}

s=pd.Series(d).explode()
import itertools
l=[*map(' '.join,itertools.product(s.index.unique(),s.unique()))]
print(s.reset_index().agg(' '.join,1).value_counts().reindex(l,fill_value=0))

horse brown    1
horse black    1
horse grey     0
duck brown     3
duck black     1
duck grey      1
dtype: int64

Since you tag panda do explode , then pass crosstab count the freq , and flatten the index with join

s=pd.Series(d).explode()
s=pd.crosstab(s.index,s).stack()
s.index=s.index.map('_'.join)
s.to_dict()
{'duck_black': 1, 'duck_brown': 3, 'duck_grey': 1, 'horse_black': 1, 'horse_brown': 1, 'horse_grey': 0}

You can use defaultdict, with default factory set to integer - this acts as a counter on all the entries in the dictionary :

from collections import defaultdict
d = defaultdict(int)
for k,v in data.items():
    for val in v:
        #combine the key with the individual values in the list
        #and get the tally/count
        d[" ".join((val,k))] += 1

d

defaultdict(int,
            {'brown horse': 1,
             'black horse': 1,
             'brown duck': 3,
             'black duck': 1,
             'grey duck': 1})

you can recursively tack on the string of the key to the desired result and keep a record of the unique solutions.

The pseudocode I would imagine using is the following:

def helper(dict, string_of_prior_keys = ""):
  list_of_strings = []
  for k in dict.keys():
    if type(dict[k]) is dict:
      list_of_strings += [helper(dict[k], k + string_of_prior_keys)]
    else:
      list_of_strings += [k + string_of_prior_keys]
  return list_of_strings

Then all you need to do is count the unique strings in that returned list of strings. I hope this helps. If I'm not clear at any point, please let me know!

Related