Multi-key combinations to access values in dictionary, python - python

i have Dictionary like this:
d={(('4', '2'), ('2', '0')): [3], (('4', '2'), ('2', '1')): [3], (('4', '2'), ('2', '3')): [1], (('4', '2'), ('2', '4')): [71]}
my target is to get the probability of some special key, for example, I need the probability of ('4', '2'), ('2', '1'), which is 3/(3+3+1+71)=3/78, but how can I write this method in python?
i have some idea like this:
p={}
for i,j in d.keys():
p[i,j]=d[i,j][0]/sum(d[i][0])
but it didn't work, because d[I] is not right.
update:
the question has been well solved with some nice answers. Now I want to ask about how to do calculations along a path in a tree that shown in the picturethe picture describes the transitions between states, and I want to find the time needed from every state to the red states.
every path in this tree has two values, for example [6,109.0], 109.0 is the time from ('4','1') to ('1','0'), and on this path, from ('4')->('4','1')->('1','0') is 10.0+109.0=119.0, so the question is how to get the time from current state to the red state?
the transitions between them could be written like this:
states_agg={((), ('2',)): [1, 0.0], (('0', '1'), ('1', '4')): [1, 10.0], (('0', '2'), ('2', '0')): [2, 10.0], (('0', '2'), ('2', '4')): [1, 159.0], (('0', '4'), ('4', '0')): [26, 13.26923076923077],
(('0', '4'), ('4', '2')): [2, 10.5],(('1', '2'), ('2', '4')): [4, 71.5], (('1', '4'), ('4', '1')): [3, 10.333333333333334], (('2',), ('2', '0')): [1, 10.0], (('2', '0'), ('0', '2')): [1, 42.0],
(('2', '0'), ('0', '4')): [6, 109.0], (('2', '1'), ('1', '2')): [3, 43.0], (('2', '3'), ('3', '2')): [1, 860.0],(('2', '4'), ('4', '2')): [76, -223.8815789473684],(('3', '2'), ('2', '0')): [1, 11.0],
(('4', '0'), ('0', '1')): [1, 507.0], (('4', '0'), ('0', '2')): [2, 69.5],(('4', '0'), ('0', '4')): [23, 200.17391304347825],(('4', '1'), ('1', '2')): [1, 95.0],(('4', '1'), ('1', '4')): [2, 1447.0],
(('4', '2'), ('2', '0')): [3, 28.666666666666668] (('4', '2'), ('2', '1'))[3,132.66666666666666], (('4', '2'), ('2', '3')): [1, 64.0],(('4', '2'), ('2', '4')): [71,79.09859154929578]}
for example from ('4', '2') to ('2', '4') the transition time is 79.09859154929578

Do you want something like the following?
d={(('4', '2'), ('2', '0')): [3],
(('4', '2'), ('2', '1')): [3],
(('4', '2'), ('2', '3')): [1],
(('4', '2'), ('2', '4')): [71]}
s = sum(v[0] for v in d.values())
p = {k: v[0]/s for k, v in d.items()}
This gives us:
>>> p
{(('4', '2'), ('2', '0')): 0.038461538461538464,
(('4', '2'), ('2', '1')): 0.038461538461538464,
(('4', '2'), ('2', '3')): 0.01282051282051282,
(('4', '2'), ('2', '4')): 0.9102564102564102}
Answering question from comments - how can I get the probability of keys begin with ('4', '1') with d as below:
d={(('4', '2'), ('2', '0')): [3], (('4', '2'), ('2', '1')): [3], (('4', '2'), ('2', '3')): [1], (('4', '2'), ('2', '4')): [71], (('4', '1'), ('1', '2')): [1], (('4', '1'), ('1', '4')): [2],}
Then we can just use a list comprehension on p:
>>> [v for k, v in p.items() if k[0] == ('4', '1')]
[0.012345679012345678, 0.024691358024691357]
And if we want the total probability of those keys:
>>> sum(v for k, v in p.items() if k[0] == ('4', '1'))
0.037037037037037035

The answer by CDJB may be what you are after.
However if your dictionary ever has keys in it for which you don't wish to use in calculating the probability (which your d[i] seems to imply) you will need to make some tweaks:
def get_prob_from_key(mykey, dikt):
numer = dikt.get(mykey)
if numer is None:
print(f"Key {mykey} not found! Can't calculate probability")
return None
denom = sum(v[0] for k, v in d.items() if mykey[0] == k[0])
return numer[0]/denom
d={(('4', '2'), ('2', '0')): [3], (('4', '2'), ('2', '1')): [3], (('4', '2'), ('2', '3')): [1], (('4', '2'), ('2', '4')): [71], (('4', '1'), ('1', '2')): [1], (('4', '1'), ('1', '4')): [2],}
k1 = (('4', '2'), ('2', '1'))
k2 = (('4', '2'), ('2', '4'))
k3 = (('5', '2'), ('2', '1'))
k4 = (('4', '1'), ('1', '2'))
get_prob_from_key(k1, d)
> 0.038461538461538464
get_prob_from_key(k2, d)
> 0.9102564102564102
get_prob_from_key(k3, d)
> Key (('5', '2'), ('2', '1')) not found! Can't calculate probability
get_prob_from_key(k4, d)
> 0.3333333333333333
A caveat:
This assumes that, like your current dictionary input, all values are lists of length 1. If that's not always the case then a change will need to be made.

Related

How to get the unique values from column on string data with file handling in python

this is how my data looks :ALL THESE DATA ARE IN SINGLE COLUMN
#columnA
(8,8)
(6,7)(7,7)(7,6)
(2,12)(12,3)(3,4)(4,12)(12,12)
(14,14)
(1,1)(1,12)(12,2)(2,2)(2,4)
(6,8)(8,8)(8,12)
(6,6)(6,3)(3,14)
(1,14)(14,14)(14,1)(1,1)(1,2)
(1,1)(1,14)
(2,2)(2,15)(15,5)(5,5)(5,16)
(1,11)(11,1)(1,2)(2,2)(2,14)
(5,5)(5,1)
(12,2)(2,2)(2,10)(10,10)
(9,9)(9,4)(4,4)
(13,13)
(1,1)
(11,14)(14,14)
for i in range(len(data)):
x.iloc[i]=data.iloc[i].unique()
output is to replace the duplicate values and find unique:
How about storing all the data in a list and find the set of the list.
for instance, if I have a list of tupples or list of lists in the form:
list = [(1,1), (2,3), (2,3), (1,3), (1,3), (1,1)]
set_of_list = set(list)
>>> {(1,3), (2,3), (1,1)}
IIUC, use pandas.Series.str.findall with explode and unique:
uniq = df['columnA'].str.findall("(\d+),(\d+)").explode().unique()
uniq
Output:
array([('8', '8'), ('6', '7'), ('7', '7'), ('7', '6'), ('2', '12'),
('12', '3'), ('3', '4'), ('4', '12'), ('12', '12'), ('14', '14'),
('1', '1'), ('1', '12'), ('12', '2'), ('2', '2'), ('2', '4'),
('6', '8'), ('8', '12'), ('6', '6'), ('6', '3'), ('3', '14'),
('1', '14'), ('14', '1'), ('1', '2'), ('2', '15'), ('15', '5'),
('5', '5'), ('5', '16'), ('1', '11'), ('11', '1'), ('2', '14'),
('5', '1'), ('2', '10'), ('10', '10'), ('9', '9'), ('9', '4'),
('4', '4'), ('13', '13'), ('11', '14')], dtype=object)

Remove an element from a lists of lists in Python [duplicate]

This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 3 years ago.
How can I remove from a list of list every list in which a '5' is placed before a '3' given an initial list of list like the following one?
[('3', '3', '3'), ('3', '3', '5'), ('3', '5', '3'), ('3', '5', '5'), ('5', '3', '3'), ('5', '3', '5'), ('5', '5', '3'), ('5', '5', '5')]
I tried with
for i in list_ck:
for j in range(0,2):
if (i[j]=='5' and i[j+1]=='3'):
list_ck.remove(i)
but it doesn't work
It's easier to test whether a 5 occurs before a 3 if they are strings, rather than tuples; so we can use ''.join to convert them to strings.
>>> data = [('3', '3', '3'), ('3', '3', '5'), ('3', '5', '3'), ('3', '5', '5'), ('5', '3', '3'), ('5', '3', '5'), ('5', '5', '3'), ('5', '5', '5')]
>>> [r for r in data if '53' not in ''.join(r)]
[('3', '3', '3'), ('3', '3', '5'), ('3', '5', '5'), ('5', '5', '5')]
This assumes you only want to test for a 5 immediately before a 3, and won't work for more general cases where the strings in the tuple could e.g. be '53' themselves. But it's sufficient for your example.
A more general solution is to use a regex, and join on a character like , which none of the strings will contain:
>>> data = [('5', '3', '1'), ('53', '1', '1'), ('5', '1', '3')]
>>> import re
>>> pattern = re.compile('(^|,)5,(.*,)*3(,|$)')
>>> [r for r in data if not pattern.search(','.join(r))]
[('53', '1', '1')]
Here the pattern (^|,)5,(.+,)*3(,|$) matches a 5 either at the start or after a ,, followed by a comma, followed by any number of things ending with commas, followed by a 3 which is either before a comma or the end of the string.
You could use a conditional list comprehension:
# List of Tuples (lot).
list_of_tups = [('3', '3', '3'), ('3', '3', '5'), ('3', '5', '3'), ('3', '5', '5'), ('5', '3', '3'), ('5', '3', '5'), ('5', '5', '3'), ('5', '5', '5')]
>>> [tup for tup in list_of_tups
if not any((a == '5' and b == '3') for a, b in zip(tup, tup[1:]))]
[('3', '3', '3'), ('3', '3', '5'), ('3', '5', '5'), ('5', '5', '5')]
To modify the list inplace rather than create a new list, create an index of items that need to be removed and then pop them off in reverse order.
idx = [n for n, tup in enumerate(list_of_tups)
if any((a == '5' and b == '3') for a, b in zip(tup, tup[1:]))]
for i in reversed(idx):
list_of_tups.pop(i)
>>> list_of_tups
[('3', '3', '3'), ('3', '3', '5'), ('3', '5', '5'), ('5', '5', '5')]
Try to create another list with the same arguments (dont copy them, create new) and remove() from the second list
tab = [('3', '3', '3'), ('3', '3', '5'), ('3', '5', '3'), ('3', '5', '5'), ('5', '3', '3'), ('5', '3', '5'), ('5', '5', '3'), ('5', '5', '5')]
tab2 = [('3', '3', '3'), ('3', '3', '5'), ('3', '5', '3'), ('3', '5', '5'), ('5', '3', '3'), ('5', '3', '5'), ('5', '5', '3'), ('5', '5', '5')]
for i in tab:
for j in range(0,2):
if i[j]=='5' and i[j+1]=='3':
tab2.remove(i)
break

Finding cycles in graph results in empty array

I am trying to find all cycles in a directed graph, I am using networks library for this. The program executes normally and results an empty array.
I am not sure how the networks library works but my use case graphs may have discontinuities in them.
I have attached the code below
import networkx as nx
G.add_nodes_from(['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18'])
G.add_edges_from([('1', '2'), ('1', '8'), ('1', '9'), ('1', '10'), ('1', '11'), ('1', '14'), ('1', '15'), ('1', '18'), ('2', '3'), ('2', '8'), ('2', '18'), ('3', '4'), ('3', '7'), ('3', '17'), ('4', '5'), ('4', '6'), ('4', '7'), ('4', '12'), ('4', '13'), ('4', '16'), ('4', '17'), ('5', '6'), ('5', '10'), ('5', '12'), ('6', '7'), ('6', '9'), ('7', '8'), ('8', '9'), ('9', '10'), ('10', '11'), ('11', '12'), ('11', '14'), ('12', '13'), ('13', '14'), ('13', '16'), ('14', '15'), ('15', '16'), ('15', '18'), ('16', '17'), ('17', '18')])
print(list(nx.simple_cycles(G)))
There are supposed to be a few cycles in my example.
Please let me know what am I doing wrong here.
print(list(nx.find_cycle(G, source=list of nodes)))

Make combination inside list of tuple

I was working on some other question . I have below list
[(['1', '2', '3'], 'abc'), (['4', '5', '6'], 'xyz')]
Output should be below
[('1', 'abc'), ('2', 'abc'), ('3', 'abc'), ('4', 'xyz'), ('5', 'xyz'), ('6', 'xyz')]
My attempt is
First i unlist the list inside it
l1=[ tuple(i[0])+(i[1],) for i in l ]
print (l1)
[('1', '2', '3', 'abc'), ('4', '5', '6', 'xyz')]
Then tried product from itertools , but it is not giving me the required result. Problem is 'abc' is getting splited in 'a','b','c' using product.
from itertools import product
[ list(product(i[:-1],i[-1])) for i in l1 ]
[[('1', 'a'),
('1', 'b'),
('1', 'c'),
('2', 'a'),
('2', 'b'),
('2', 'c'),
('3', 'a'),
('3', 'b'),
('3', 'c')],
[('4', 'x'),
('4', 'y'),
('4', 'z'),
('5', 'x'),
('5', 'y'),
('5', 'z'),
('6', 'x'),
('6', 'y'),
('6', 'z')]]
Use list comprehension:
L=[(['1', '2', '3'], 'abc'), (['4', '5', '6'], 'xyz')]
In: [ (n,s) for l,s in L for n in l ]
Out:
[('1', 'abc'),
('2', 'abc'),
('3', 'abc'),
('4', 'xyz'),
('5', 'xyz'),
('6', 'xyz')]
As you can write:
rslt=[]
for l,s in L:
for n in l:
rslt.append((n,s))
product from itertools is working as intended. The issue is that Python strings are iterable, so product is iterating through the elements of the string. If you want to treat the string as a single element, you can put it into a list and feed the list to product
You can use itertools.product as long as you wrap the string in an iterable so that it is handled as a single element of an iterable rather than iterated.
from itertools import product
data = [(['1', '2', '3'], 'abc'), (['4', '5', '6'], 'xyz')]
combos = [combo for a, b in data for combo in product(a, [b])]
print(combos)
# [('1', 'abc'), ('2', 'abc'), ('3', 'abc'), ('4', 'xyz'), ('5', 'xyz'), ('6', 'xyz')]
You can use list comprehensions:
ls = [(['1', '2', '3'], 'abc'), (['4', '5', '6'], 'xyz')]
ls_new = [(a,b) for n,b in ls for a in n]
print(ls_new)

How to delete similar value from a list and print the remaining

list =[('1', '5'), ('3', '5'), ('4', '5'), ('5', '1'), ('5', '3'), ('5', '4')]
above is a generated list now i want to write only (5,1) for (1,5) and (5,1) too same with the other values.
Desired output
list = [('5', '1'), ('5', '3'), ('5', '4')]
Add the item to the new list if its reverse is not also in the list, or the item is larger than its reverse.
newlist = []
for item in oldlist:
rev = item[::-1]
if (not (rev in oldlist)) or (item > rev)
newlist.append(item)
l = [('1', '5'), ('3', '5'), ('4', '5'), ('5', '1'), ('5', '3'), ('5', '4')]
s=set()
for e in l:
if e[0] >= e[1]:
s.add(e)
else:
s.add((e[1], e[0]))
l = list(s)
Note: it doesn't preserve the order. If that is important:
s=set(); l2 = []
for e in l:
if e[0] < e[1]:
e = (e[1], e[0])
if not e in s:
s.add(e)
l2.append(e)
li =[('1', '5'), ('3', '5'), ('4', '5'), ('5', '1'), ('5', '3'), ('5', '4')]
gen = ((a,b) if a>b else (b,a) for a,b in li)
lu = []
[lu.append(y) for y in gen if y not in lu]
print lu
If order isn't important, you can achieve this with the list and set functions in a one liner like the following:
orig_list =[('1', '5'), ('3', '5'), ('4', '5'), ('5', '1'), ('5', '3'), ('5', '4')]
modified_list = list(set([(t[0], t[1]) if t[0] > t[1] else (t[1], t[0]) for t in orig_list]))
Concise, if a bit dense.
my_list = [('1', '5'), ('3', '5'), ('4', '5'), ('5', '1'), ('5', '3'), ('5', '4')]
new_list = [(a, b) if (a > b) else (b, a) for a, b in my_list]
result = list(set(new_list))

Categories

Resources