Dear All

I am working with a tab-delimeted files - first two columns are pairs of identifiers and third column is floating point number (0-1) denoting interaction strength between colmn1 and 2. sample file is also attached.


eg-

column1 column2 column3

john steve 0.67588
john matt 1.00
red blue 0.90
yellow steve 0.02

and so on...

from this file I need to know for each unique identifier in first column how many connections are there in second column (example john have two connections and red and yellow have one) at different threshold (column3) from 0 to 1. and writing an output to a file.

the final output look something like this -

for column3 >= 0.6

john 2
red 1
yellow 0

Thanks..

Dani AI

Generated

A few clarifications that change the implementation choices: decide whether duplicates in column2 should count separately or not (unique neighbor vs. multi-edge), whether the network is directed (count only when the identifier is in column1) or undirected (treat pair order as the same), and whether thresholds are inclusive. Also watch for a header line or malformed rows and convert strengths to floats before comparing.

, and give good starting points (per-id storage, counters, and grouping). For small files a simple per-id list and a comprehension is fine. If you must evaluate many thresholds per id or the file is large, avoid re-scanning every list for every threshold: sort strengths once and use binary search to get the count quickly, or use a table-based tool like pandas for concise code and vectorized operations.

Efficient option for many thresholds (per-id sorted strengths + binary search):

from bisect import bisect_left
from collections import defaultdict

vals = defaultdict(list)
with open('input.tsv') as f:
    next(f)           # skip header if present
    for line in f:
        a, b, s = line.rstrip().split()
        vals[a].append(float(s))

for a in vals:
    vals[a].sort()

thresholds = [0.0, 0.25, 0.5, 0.75, 1.0]
with open('counts.tsv', 'w') as out:
    out.write('threshold\tid\tcount\n')
    for t in thresholds:
        for a, lst in vals.items():
            idx = bisect_left(lst, t)
            out.write(f"{t}\t{a}\t{len(lst) - idx}\n")

If you want unique neighbors (one connection per distinct column2), first collect the best/last strength per neighbor (per-id dict of neighbor->strength), then sort those strengths.

Pandas makes thresholds and unique-count logic concise and handles larger-than-memory workflows with chunking or Dask. See pandas groupby docs for details: pandas.DataFrame.groupby. For binary-search details see the stdlib docs: bisect.

Recommended Answers

All 3 Replies

From your description, column2 seems to be unnecessary. If that is the case, you
can read and store your data in a dictionary in the structure below:

connections = {'john':[0.67588, 1.00],
               'red':[0.9],
              }

If you want to print for column3 > 0.06:

for id in connections:
    print id, len([x for x in connections[id] if x > 0.06])

There are several different ways to do this. One is a dictionary pointing to a list that contains the number of records found for the key, and the thresholds found to test if greater than (if I am reading the question correctly). You could also use two dictionaries, one as the counter, and one to hold the thresholds if that is easier to understand. An SQL file would be in order if this is a large data set. You could also create a class instance for each unique name, but that is probably more trouble and more confusing than the other solutions. A simple example:

test_list = [
"john steve 0.67588",
"john matt 1.00",
"red blue 0.90",
"yellow steve 0.02" ]

test_dict = {}
for rec in test_list:
    substrs = rec.split()
    key = substrs[0]
    if key not in test_dict:
        ## add the new key, counter=1, and a list containing the threshold
        test_dict[key] = [1, [float(substrs[2])]]
    else:
        test_dict[key][0] += 1     ## add one to counter (zero location in list
        test_dict[key][1].append(float(substrs[2]))   ## interaction strength

for key in test_dict:
    ## are any > 0.5
    values = test_dict[key][1]
    for v in values:
        if v > 0.5:
            print key, v, test_dict[key][0]

This would produce your desired output:

import itertools as it

data="""john steve 0.67588
john matt 1.00
red blue 0.90
yellow steve 0.02"""

data_pairs = sorted((first, value)
                    for first,second,value in (d.split()
                                               for d in data.splitlines()))
limit = 0.6
for name, group in it.groupby(data_pairs, lambda x: x[0]):
    print name, len([ value for _,value in group if float(value) >= limit])
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.