Related
Let's say I have a list of tuples like so:
The second index of the tuple is a count of how many times the first index appeared in a dataset.
[(24, 11),
(12, 10), (48, 10),
(10, 9), (26, 9), (59, 9), (39, 9), (53, 9), (21, 9), (52, 9), (50, 9),
(41, 8), (33, 8), (44, 8), (46, 8), (38, 8), (20, 8), (57, 8),
(23, 7), (6, 7), (3, 7), (37, 7), (51, 7),
(34, 6), (54, 6), (36, 6), (14, 6), (17, 6), (58, 6), (15, 6), (29, 6),
(13, 5), (32, 5), (9, 5), (40, 5), (45, 5), (1, 5), (31, 5), (11, 5), (30, 5), (5, 5), (56, 5), (35, 5), (47, 5),
(2, 4), (19, 4), (42, 4), (25, 4), (43, 4), (4, 4), (18, 4), (16, 4), (49, 4), (8, 4), (22, 4), (7, 4), (27, 4),
(55, 3),
(28, 2)]
Example
(24, 11) = (number, count)
As you can see there are multiples of the same number in the second index. Is there a way you could collect the first six of the counts and put them into another list?
For example collect all the 11, 10, 9, 8, 7 counts and so on and then generate a number of six in length from that collection.
I am trying to generate a random number from the 6 most common numbers.
Update
This is how I managed to do it
def get_highest_lotto_count(data) -> list:
"""Takes all numbers from 2nd index then extracts the top 6 numbers"""
numbers = data["lotto"]
highest_count_numbers: list = [num[1] for num in numbers]
high_count_nums = list(set(highest_count_numbers))
high_count_nums.reverse()
return high_count_nums[:6]
data["lotto"] is the list provided above. I stripped all the 2nd index numbers (the counts) and converted to a set to remove duplicates.
This then gave me all the counts, I then took the first six from the reversed list.
def common_lotto_generator() -> list:
"""
This takes the top 6 numbers from get_highest_lotto_count and generates a list
from the all the numbers that have the same 2nd index.
Then generates a random 6 digit number from the list.
"""
high_count_numbers = get_highest_lotto_count(collect_duplicate_lotto_numbers())
data = collect_duplicate_lotto_numbers()
numbers = data["lotto"]
common_number_drawn: list = [
num[0] for num in numbers if num[1] in high_count_numbers
]
return random.sample(common_number_drawn, 6)
Then I called the above function to get the list of 6 numbers and the added the data again so i could get all the tuples that matched the 2nd index from the list of 6.
Your question is a bit unclear. You could try:
from heapq import nlargest
from random import choice
pairs = [(24, 11),
(12, 10), (48, 10),
...
(28, 2)
]
top_counts = set(nlargest(6, set(count for _, count in pairs)))
top_counts_numbers = [
number for number, count in pairs if count in top_counts
]
print(choice(top_counts_numbers))
The first part uses heapqs nlargest() to get the 6 largest counts: {6, 7, 8, 9, 10, 11}. As mentioned by others, that isn't exactly the counts you provide. Your wording here is a bit fuzzy. You could also use sorted() to do that. (I'm converting the result into a set because sets provide a fast lookup, which is done in the next step. But you don't need that.)
Selecting the corresponding numbers via a list comprehension:
[24, 12, 48, 10, 26, 59, 39, 53, 21, 52, 50, 41, 33, 44, 46, 38, 20, 57, 23,
6, 3, 37, 51, 34, 54, 36, 14, 17, 58, 15, 29]
Using choice() to select a random number from them.
I'm not complete sure whether the solution below answers your question. I'm puzzled because the top 6 count does not include the 7 and 8 frequency (whereas you seem to hint at this in your last comment).
The code sorts the tuples based on the second key and subsequently selects its entries at random.
#!/usr/local/bin/python3
import random
# Tuplelist
TupleList = [(24, 11),
(12, 10), (48, 10),
(10, 9), (26, 9), (59, 9), (39, 9), (53, 9), (21, 9), (52, 9), (50, 9),
(41, 8), (33, 8), (44, 8), (46, 8), (38, 8), (20, 8), (57, 8),
(23, 7), (6, 7), (3, 7), (37, 7), (51, 7),
(34, 6), (54, 6), (36, 6), (14, 6), (17, 6), (58, 6), (15, 6), (29, 6),
(13, 5), (32, 5), (9, 5), (40, 5), (45, 5), (1, 5), (31, 5), (11, 5), (30, 5), (5, 5), (56, 5), (35, 5), (47, 5),
(2, 4), (19, 4), (42, 4), (25, 4), (43, 4), (4, 4), (18, 4), (16, 4), (49, 4), (8, 4), (22, 4), (7, 4), (27, 4),
(55, 3),
(28, 2)]
# Sort tuples
TupleList.sort(key = lambda x: x[1])
# Select most frequent tuples
NumberOfMaxElements = 6
MaxElements = TupleList[-NumberOfMaxElements:]
print("Most frequent tuples:")
print(MaxElements)
# Random draws
print("Some random draws:")
NumberOfValues = 20
for iter in range(NumberOfValues):
RandomElement = random.randint(0, NumberOfMaxElements-1)
RandomDraw = MaxElements[RandomElement][0]
print(RandomDraw)
I have a list of lists of tuples. Each inner list contains 3 tuples, of 2 elements each:
[
[(3, 5), (4, 5), (4, 5)],
[(7, 13), (9, 13), (10, 13)],
[(5, 7), (6, 7), (7, 7)]
]
I need to get a single list of 3 tuples, summing all these elements "vertically", like this:
(3, 5), (4, 5), (4, 5)
+ + + + + +
(7, 13), (9, 13), (10, 13)
+ + + + + +
(5, 7), (6, 7), (7, 7)
|| || ||
[(15, 25), (19, 25), (21, 25)]
so, for example, the second tuple in the result list is given by the sums of the second tuples in the initial list
(4+9+6, 5+13+7) = (19, 25)
I'm trying with list/tuple comprehensions, but I'm getting a little lost with this.
You can use zip and sum for something a little longer, but without the heavyweight dependency on numpy if you aren't already using it.
>>> [tuple(sum(v) for v in zip(*t)) for t in zip(*x)]
[(15, 25), (19, 25), (21, 25)]
The outer zip pairs the corresponding tuples together; the inner zip pairs corresponding elements of those tuples together for addition.
You could do this pretty easily with numpy. Use sum on axis 0.
import numpy as np
l = [
[(3, 5), (4, 5), (4, 5)],
[(7, 13), (9, 13), (10, 13)],
[(5, 7), (6, 7), (7, 7)]
]
[tuple(x) for x in np.sum(l,0)]
Output
[(15, 25), (19, 25), (21, 25)]
You could do this with pure python code.
lst = [
[(3, 5), (4, 5), (4, 5)],
[(7, 13), (9, 13), (10, 13)],
[(5, 7), (6, 7), (7, 7)]
]
lst2 = []
for a in range(len(lst[0])):
l = []
for i in range(len(lst)):
l.append(lst[i][a])
lst2.append(l)
output = []
for a in lst2:
t = [0 for a in range(len(lst[0][0]))]
for i in range(len(a)):
for z in range(len(a[i])):
t[z]+= a[i][z]
output.append(tuple(t))
print(output)
if you change the list then its is works.
output
IN:
lst = [
[(3, 5), (4, 5), (4, 5)],
[(7, 13), (9, 13), (10, 13)],
[(5, 7), (6, 7), (7, 7)]
]
OUT:
[(15, 25), (19, 25), (21, 25)]
IN:
lst = [
[(3, 5,2), (4, 5,3), (4, 5,1)],
[(7, 13,1), (9, 13,3), (10, 13,3)],
[(5, 7,6), (6, 7,3), (7, 7,7)]
]
OUT:
[(15, 25, 9), (19, 25, 9), (21, 25, 11)]
data = [
[(3, 5), (4, 5), (4, 5)],
[(7, 13), (9, 13), (10, 13)],
[(5, 7), (6, 7), (7, 7)]
]
result = [tuple(sum(x) for x in zip(*t)) for t in zip(*data)]
print(result)
This is a one-liner, I don't think you can get more pythonic than this.
I am exploring neural network simulations between these "neurons" that you see in the figure below. The difficulty I have is connecting each neuron to its nearest neighbor. I first figured that I could do it by tuple unpacking, but it has become very complicated.
def _connect_cells(self):
for source, target in zip(self.cells, self.cells[1:] + [self.cells[0]]):
nc = h.NetCon(source.soma(0.5)._ref_v, target.syn, sec=source.soma)
nc.weight[0] = self._syn_w
nc.delay = self._syn_delay
source._ncs.append(nc)
In this example code snippet, the tuple unpacking is configured such that the i th neuron connects to i + 1 th neuron until neuron n. When it reaches neuron n, the n th neuron will connect back to the first neuron. This tuple unpacking is for a network structure resembling a ring of neurons.
However, in my case, the structure is a grid of n x n neurons. The list bellow corresponds to the neurons:
20 21 22 23 24
15 16 17 18 19
10 11 12 13 14
5 6 7 8 9
0 1 2 3 4
The above tuple unpacking would not work for this because neuron 4 is not supposed to connect to neuron 5. The list goes exclusively left to right due to how the neurons are created. The exact connection that I am trying to achieve is shown in the figure below. It is possible to do it manually (it would take a lot of code), but how can I approach it with a for loop in the same way as the example code?
Connection matrix
If I understand correctly you want each neuron in a square grid connect to each neighbouring neuron, horizontally, vertically or diagonally.
This will do the job:
def connect(side):
maxcol = side-1
maxrow = side*maxcol
neurons = list(range(side**2))
conns = []
for col in range(side):
for row in range(0, side**2, side):
if col < maxcol: #connect left
conns.append((neurons[row+col],neurons[row+col+1]))
if row > 0: #connect left up
conns.append((neurons[row+col],neurons[row+col+1-side]))
if row < maxrow: #connect left down
conns.append((neurons[row+col],neurons[row+col+1+side]))
if row < maxrow: #connect down
conns.append((neurons[row+col],neurons[row+col+side]))
return conns
connect(5)
[(0, 1), (0, 6), (0, 5), (5, 6), (5, 1), (5, 11), (5, 10), (10, 11), (10, 6), (10, 16), (10, 15), (15, 16), (15, 11), (15, 21), (15, 20), (20, 21), (20, 16), (1, 2), (1, 7), (1, 6), (6, 7), (6, 2), (6, 12), (6, 11), (11, 12), (11, 7), (11, 17), (11, 16), (16, 17), (16, 12), (16, 22), (16, 21), (21, 22), (21, 17), (2, 3), (2, 8), (2, 7), (7, 8), (7, 3), (7, 13), (7, 12), (12, 13), (12, 8), (12, 18), (12, 17), (17, 18), (17, 13), (17, 23), (17, 22), (22, 23), (22, 18), (3, 4), (3, 9), (3, 8), (8, 9), (8, 4), (8, 14), (8, 13), (13, 14), (13, 9), (13, 19), (13, 18), (18, 19), (18, 14), (18, 24), (18, 23), (23, 24), (23, 19), (4, 9), (9, 14), (14, 19), (19, 24)]
I'm importing data from a .json file, where I transformed the dictionary into a list of tuples. These tuples represent the data as a timestamp and a value marked at that specified timestamp, such as this example:
participant_1 = [(1, 8), (2, 2), (3, 2), (4, 1), (5, 3), (6, 5), (7, 6), (8, 6), (9, 8), (10, 9), (11, 9), (12, 9), (13, 3), (14, 3), (15, 4), (16, 5), (17, 6), (18, 6), (19, 7), (20, 8), (21, 8), (22, 9), (23, 9), (24, 9), (25, 9), (26, 9), (27, 9)]
participant_2 = [(1, 5), (2, 5), (3, 1), (4, 3), (5, 4), (6, 5), (7, 5), (8, 7), (9, 8), (10, 9), (11, 10), (12, 10), (13, 10), (14, 10), (15, 10), (16, 10), (17, 10), (18, 0), (19, 0), (20, 0), (21, 0), (22, 0), (23, 0), (24, 0), (25, 0), (26, 0), (27, 0)]
I'll have multiple lists (of multiple participants) where the timestamp (first value of the tuple) will not change but the second (marked value) will. What I want to do is plot a graph where I can compare the marked values (therefore, the x-axis will be the time and the y-axis the marked values).
The way I want to compare the data is by horizontal bars where a different color would represent the marked value. These values range from 0 - 10. Thus, for each of these values, I would like to assign a color. In this way, there would be multiple horizontal bars, for each participant, and for each marked value, a different color (so that I can see the differences between the marked values of participants).
I do not wish for multiple bars for each participant - more like a stacked graph where the marked value would be one color, and those change according to the timestamp. In this way, I would be able to compare the marked values of the participants in a timeframe. I have an example from a paper:
Example
However, I couldn't find any way to do this yet.
Thanks.
You could convert each list to a dataframe, using the timestamp as index. The concatenation of these lists as columns to an assembling dataframe can be shown as a heatmap.
Here is some example code:
from matplotlib import pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
participant_1 = [(1, 8), (2, 2), (3, 2), (4, 1), (5, 3), (6, 5), (7, 6), (8, 6), (9, 8), (10, 9), (11, 9), (12, 9), (13, 3), (14, 3), (15, 4), (16, 5), (17, 6), (18, 6), (19, 7), (20, 8), (21, 8), (22, 9), (23, 9), (24, 9), (25, 9), (26, 9), (27, 9)]
participant_2 = [(1, 5), (2, 5), (3, 1), (4, 3), (5, 4), (6, 5), (7, 5), (8, 7), (9, 8), (10, 9), (11, 10), (12, 10), (13, 10), (14, 10), (15, 10), (16, 10), (17, 10), (18, 0), (19, 0), (20, 0), (21, 0), (22, 0), (23, 0), (24, 0), (25, 0), (26, 0), (27, 0)]
participants = [participant_1, participant_2]
names = ['participant 1', 'participant 2']
pd.concat({name: pd.DataFrame(particip_data, columns=['timestamp', name]).set_index('timestamp')
for name, particip_data in zip(names, participants)}).reset_index()
full_df = pd.concat([pd.DataFrame(particip_data, columns=['timestamp', name]).set_index('timestamp')
for name, particip_data in zip(names, participants)],
axis=1)
fig, ax = plt.subplots(figsize=(15, 3))
cmap = plt.get_cmap('turbo', 11)
sns.heatmap(ax=ax, data=full_df.T, annot=True,
cmap='turbo', vmin=-0.5, vmax=10.5, cbar_kws={'ticks': np.arange(11), 'pad': 0.02})
ax.tick_params(labelrotation=0)
plt.tight_layout()
plt.show()
I have completed some rather intensive calculations, and i was not able to save my results in pickle (recursion depth exceded), so i was forced to print all the data and save it in a text file.
Is there any easy way to now convert my list of tuples in text to well... list of tuples in python? the output looks like this:
[(10, 5), (11, 6), (12, 5), (14, 5), (103360, 7), (16, 6), (102725, 7), (17, 6), (18, 5), (19, 9), (20, 6), ...(it continues for 60MB)]
You can use ast.literal_eval():
>>> s = '[(10, 5), (11, 6), (12, 5), (14, 5)]'
>>> res = ast.literal_eval(s)
[(10, 5), (11, 6), (12, 5), (14, 5)]
>>> res[0]
(10, 5)
string = "[(10, 5), (11, 6), (12, 5), (14, 5), (103360, 7), (16, 6), (102725, 7), (17, 6), (18, 5), (19, 9), (20, 6)]" # Read it from the file however you want
values = []
for t in string[1:-1].replace("),", ");").split("; "):
values.append(tuple(map(int, t[1:-1].split(", "))))
First I remove the start and end square bracket with [1:-1], I replace ), with ); to be able to split by ; so that the it foesn't split by the commas inside the tuples as they are not preceded by a ). Inside the loop I'm using [1:-1] to remove the parenthesis this time and splitting by the commas. The map part is to convert the numeric strs into ints and I'm appending them as a tuple.