in reply to Tallying appearance of a unique string from hash keys

Let me be sure I understand the question.

We have a file with lines. Each line contains an ID followed by a tab followed by another ID. You want to know how many times each ID appears in the file, that's called the degree. And then you want to summarize how many times each degree appears.

If so then this should solve the problem:

#! /local/bin/perl use strict; use warnings; my %degree; my $filename = "edges.txt"; open(my $fh, "<", $filename) or die "Can't open '$filename': $!"; while (<$fh>) { if (/(\S+)\t(\S+)/) { $degree{$1}++; $degree{$2}++; } } my %degree_distribution; $degree_distribution{$_}++ for values %degree; for my $id (sort keys %degree) { my $d = $degree{$id}; my $freq = $degree_distribution{$d}; print "$id has degree:\t$d\t(freq: $freq)\n"; }
If this is not the question you are asking, please clarify your question. Showing us a small example would be best. For example give us 5-20 lines of input and what output you'd expect from that.

Replies are listed 'Best First'.
Re^2: Tallying appearance of a unique string from hash keys
by jack_j (Initiate) on Mar 27, 2009 at 19:32 UTC
    Hello, So I've progressed in my script (for a newbie), but still have some gaps that I could use some help on if anyone is able to help.
    #! /local/bin/perl use strict; use warnings; #Declare hash to pull IDs and corresponding degrees into from file my %degree; my %newdegree; my @geneID_1; my @geneID_2; my $filename = "edges.txt"; #Set a variable for our file name open(my $fh, "<", $filename) or die "Can't open file $filename."; #Op +en the file edges.txt while (<$fh>) { if ($_ =~ m/(\S+)\t(\S+)/) { #Match the IDs in the file to + $1 and $2 $degree{$1}++; #Count the appearance of each + ID, and store this as $degree{$2}++; #the value for that key (this + will be the degree) push (@geneID_1, $1); push (@geneID_2, $2); }} close $fh; #Close the file edges.txt #Calling the following subroutines DegreeDistribution(); RandomSequence(); DegreeRan(); #Subroutines can be found below sub DegreeDistribution{ #Determines the degree distribution (i.e. fre +quency of each degree) my %degree_distribution; $degree_distribution{$_}++ for values %degree; #Creates a hash wi +th the keys as the degrees and the values as the frequencies for my $id (keys %degree) { #This corresponds each b +elow to it's key my $d = $degree{$id}; #This is the degree value +corresponding to its gene ID my $freq = $degree_distribution{$d}; #This is the frequency val +ue corresponding to its gene ID??? print "$id has degree:\t$d\t(freq: $freq)\n"; }} sub RandomSequence{ #Generates a hash of random ID interactions and + each IDs degree my $length = scalar (@geneID_1); for (my $i=0; $i<$length; $i++){ my $ID = int(rand($length)); my $new_id1 = $geneID_1[$ID]; my $new_id2 = $geneID_2[$ID]; $newdegree{$new_id1}++; $newdegree{$new_id2}++; }} sub DegreeRan{ #same as sub DegreeDistribution but for the random +sequence my %degree_distribution; $degree_distribution{$_}++ for values %newdegree; #Creates a hash + with the keys as the degrees and the values as the frequencies for my $id (keys %degree) { #This corresponds each b +elow to it's key my $d = $degree{$id}; #This is the degree value +corresponding to its gene ID my $freq = $degree_distribution{$d}; #This is the frequency val +ue corresponding to its gene ID??? print "$id has degree:\t$d\t(freq: $freq)\n"; }} exit;
    I have a few concerns: 1. I want to create three random networks, not just one. I'm not sure how to make my subroutine so that it produces a different hash each time (i.e. named differently), than I can return to the main script -- the return function didn't seem to work properly, it only returns one key-value pair not the whole list. 2. Similar to one, I want to run each hash through the DegreeDistribution subroutine, because making a separate subroutine for each hash defeats the purpose of a subroutine. 3. Probably also very related, I want to return the final values to the program so I can use them all (from the original dataset and the three random datasets) in an excel file. Thank you to anyone that responds.
      First of all how to pass a hash:
      # Populate a hash. my %result = some_function(%data); sub some_function { my %passed = @_; my %to_return; # Do stuff with %passed here and populate %to_return return %to_return; }
      With this you can do things like this:
      my %distribution = degree_distribution(); my %random_distribution_1 = random_distribution(); my %random_distribution_2 = random_distribution(); my %random_distribution_3 = random_distribution(); output(%distribution); output(%random_distribution_1); output(%random_distribution_2); output(%random_distribution_3);
      and so on. (I'm not suggesting that those be actual functions you use, but that gives you an idea.)

      Before long I predict that having to repetitively work with 3 random distributions will get very old. That's where you'll want to work with more complex data structures. For that read references quick reference and come back if you have any questions.

        Hello, I've discovered that my random hashes based on my above code are not actually random, but are biased based on the original network. What I should do is outlined in my pseudocode, some elements of which I am having trouble with:
        #read IDs into %edges using match operator /(\S*)(\t)(\S*)/ and specia +l variables $1, $3 for each ID per line #assign IDs as format $edge{ID1,ID2} #skip edge assignment if ID2,ID1 already exists .. the network needs t +o be undirected such that ID2-ID1 is equivalent to ID1-ID2 and should + therefore not be counted twice #populate hash of unique IDs from %edges #create array of unique IDs from hash of unique IDs .... @uniqIDs, $un +iqIDs[0]=ID1, uniqIDs[1]=ID2 etc .. how do i do this? #initialize degree counter hash (IDs are keys, values are degrees) usi +ng @uniqIDs with foreach #go through %edges and increment %counter for each ID #generate random network with rand(int(scalar(@uniqIDs))), discard ran +dom picks if they already exist or represent undirected equivalent #initialize random network degree counter hash, and then count random +network degrees as before
        I'm already stuck at how to skip an edge assignment if $2,$1 exists. Then, how can I populate a new hash of unique IDs? Again, the problem of excluding something if it already exists.
        my $filename = "edges.txt"; #Set a variable for our file name open(my $fh, "<", $filename) or die "Can't open file $filename."; #Op +en the file edges.txt while (<$fh>) { if ($_ =~ m/(\S+)\t(\S+)/) { #Match the IDs in the fil +e to $1 and $2 $edge{$1,$2}= $holder; #assign IDs as format $edge +{ID1,ID2} close $fh; #Close the file edges.txt my @list = keys %uniqedge; print "@list\n"; #Prints the list of keys, but they are un +i-directional (i.e. repeated for ID1-ID2 and ID2-ID1)
        Once I have these steps, I can proceed to counting and using the unique IDs list to create my random networks.
Re^2: Tallying appearance of a unique string from hash keys
by jack_j (Initiate) on Mar 26, 2009 at 06:26 UTC
    Thank you very much! Let me just make sure it's doing what I want it to (being such a large dataset I can't confirm the output manually). The degree is the number of times each ID appears. The frequency is the number of times that degree appears in the dataset. I have another aspect to this I was wondering if you guys could help me out with. I have to create three random networks with the same number of IDs and interactions (but since they are random, the actual interactions will be different). And do the same degree and frequency calculations (to compare to this network) -- A subroutine would be most useful. Lastly, I need to export this all to an excel file using the Spreadsheet::WriteExcel module (with headers of the separate columns being the degrees (data in ascending order) and the corresponding degree frequencies for the given network and each of the three randomized networks). Thank you in advance to anyone that can help!
      That is exactly what that snippet of code does.

      As for the rest of it, nuh uh, that isn't how it works. This is a place for people to learn about programming, not a place for people to get their projects done by others. If I think that I can give you a little help and you can try the rest, I may donate a little effort. If you want to demand a detailed spec and show no evidence of putting any of your own effort in, that sounds like real work. I'm perfectly willing to discuss my hourly rate with you, but I won't contribute anything more for free.

        Sorry guys, Thank you for the help. If I get stuck along the way I'll ask for some pointers.

      PerlMonks is not a code-writing service. You must at least make some minimal effort on your own. Start by trying to write your own subroutine; if you get stuck, feel free to come back and ask more specific questions, and show your code!

      HTH,

      planetscape
        Hello, I'm not sure how exactly to create a three random networks of these IDs. If I reorder either $1 or $2, I would accomplish this, then simply use the code above to determine the degrees and frequencies of this new network. What functions would allow me to change the order of the ID pairs in the keys of this hash, or change the order of $1 and/or $2 and place them into a new hash? Any help would be appreciated!