python - Stacking Arrays in Numpy: Forskellige adfærd mellem UNIX og Windows

Indlæg af Hanne Mølgaard Plasc

Problem



Bemærk: Dette er Python 2.7, ikke Py3


Dette er et opdateret forsøg på at stille et tidligere spørgsmål. Du har bedt om min komplette kode og forklaring af indhold, og f.eks. Uddatafiler. Jeg vil prøve mit bedste for at formatere dette godt.


Denne kode er beregnet til at tage en inputfil fra en fluorometrisk 'pladelæser' og konvertere aflæsningerne til DNA-koncentrationer og masser. Det genererer derefter en uddatafil organiseret i henhold til en 8x12 pladeplan (standard for DNA/molekylær arbejde). Rækker er mærket 'A, B, C, ..., H' og kolonner er mærket simpelthen 1-12.


Baseret på brugerindgang skal arrayer stables for at formatere output. Men når arrayer er stablet i UNIX (og enten trykt eller skrevet til en outfile), er de begrænset til det første tegn .


Med andre ord, i Windows, hvis et tal i arrayet er 247,5, udskriver det hele nummeret. Men i et UNIX-miljø (Linux/Ubuntu/MacOS) bliver det afkortet til simpelthen '2'. Et tal, der er -2,7, vil normalt udskrive i Windows, men i UNIX udskrives der blot som '-'.


Den komplette kode kan findes nedenfor; Bemærk, at den sidste del er den mest relevante del af koden :


#!/usr/bin/env python

Usage = """
plate\_calc.py - version 1.0

Convert a series of plate fluorescence readings
to total DNA mass per sample and print them to 
a tab-delimited output file.

This program can take multiple files as inputs
(separated by a space) and generates a new
output file for each input file.

NOTE: 

1) Input(s) must be an exported .txt file.
2) Standards must be in columns 1 and 2, or 11 
and 12.
3) The program assumes equal volumes across wells.

Usage:

    plate\_calc.py input.txt input2.txt input3.txt
"""

import sys
import numpy as np

if len(sys.argv)<2:
    print Usage
else:
#First, we want to extract the values of interest into a Numpy array
    Filelist = sys.argv[1:]
    input\_DNA\_vol = raw\_input("Volume of sample used for AccuClear reading (uL): ")
    remainder\_vol = raw\_input("Remaining volume per sample (uL): ")
    orientation = raw\_input("Are the standards on the LEFT (col. 1 & 2), or on the RIGHT (col. 11 and 12)? ")
    orientation = orientation.lower()
    for InfileName in Filelist:
        with open(InfileName) as Infile:
            fluor\_list = []
            Linenumber = 1
            for line in Infile: #this will extract the relevant information and store as a list of lists
                if Linenumber == 5:
                    line = line.strip('
').strip('
').strip('	').split('	')
                    fluor\_list.append(line[1:])
                elif Linenumber > 5 and Linenumber < 13:
                    line = line.strip('
').strip('
').strip('	').split('	')
                    fluor\_list.append(line)
                Linenumber += 1
            fluor\_list = [map(float, x) for x in fluor\_list] #converts list items from strings to floats
            fluor\_array = np.asarray(fluor\_list) #this takes our list of lists and converts it to a numpy array


Denne del af koden (ovenfor) ekstraherer værdierne af interesse fra en inputfil (opnået fra pladelæser) og konverterer dem til en matrix. Det tager også brugerindgang for at få oplysninger til beregninger og konverteringer, og også for at bestemme kolonnerne, hvor standarderne er placeret.


Den sidste del kommer i spil senere, når arrays er stablet - det er her den problematiske opførsel forekommer.


        #Create conditional statement, depending on where the standards are, to split the array
        if orientation == "right":
            #Next, we want to average the 11th and 12th values of each of the 8 rows in our numpy array 
            stds = fluor\_array[:,[10,11**] #Creates a sub-array with the standard values (last two columns, (8x2))
            data = np.delete(fluor\_array,(10,11),axis=1) #Creates a sub-array with the data (first 10 columns, (8x10))

        elif orientation == "left":
            #Next, we want to average the 1st and 2nd values of each of the 8 rows in our numpy array   
            stds = fluor\_array[:,[0,1**] #Creates a sub-array with the standard values (first two columns, (8x2))
            data = np.delete(fluor\_array,(0,1),axis=1) #Creates a sub-array with the data (last 10 columns, (8x10))

        else:
            print "Error: answer must be 'LEFT' or 'RIGHT'"

        std\_av = np.mean(stds, axis=1) #creates an array of our averaged std values

        #Then, we want to subtract the average value from row 1 (the BLANK) from each of the 8 averages (above)
        std\_av\_st = std\_av - std\_av[0]

        #Run a linear regression on the points in std\_av\_st against known concentration values (these data = y axis, need x axis)
        x = np.array([0.00, 0.03, 0.10, 0.30, 1.00, 3.00, 10.00, 25.00])*10 #ng/uL*10 = ng/well
        xi = np.vstack([x, np.zeros(len(x))]).T #creates new array of (x, 0) values (for the regression only); also ensures a zero-intercept (when we use (x, 1) values, the y-intercept is not forced to be zero, and the slope is slightly inflated)
        m, c = np.linalg.lstsq(xi, std\_av\_st)[0] # m = slope for future calculations

        #Now we want to subtract the average value from row 1 of std\_av (the average BLANK value) from all data points in "data"
        data\_minus\_blank = data - std\_av[0]

        #Now we want to divide each number in our "data" array by the value "m" derived above (to get total ng/well for each sample; y/m = x)
        ng\_per\_well = data\_minus\_blank/m

        #Now we need to account for the volume of sample put in to the AccuClear reading to calculate ng/uL
        ng\_per\_microliter = ng\_per\_well/float(input\_DNA\_vol)

        #Next, we multiply those values by the volume of DNA sample (variable "ng")
        ng\_total = ng\_per\_microliter*float(remainder\_vol)

        #Set number of decimal places to 1
        ng\_per\_microliter = np.around(ng\_per\_microliter, decimals=1)
        ng\_total = np.around(ng\_total, decimals=1)


Ovennævnte kode udfører de nødvendige beregninger for at finde ud af koncentrationen (ng/uL) og total masse (ng) af DNA i en given prøve baseret på en lineær regression af DNA-standarderne, som enten kan være i kolonne 1 og 2 (brugerindgang='venstre') eller i kolonne 11 og 12 (brugerindgang='højre').


        #Create a row array (values A-H), and a filler array ('-') to add to existing arrays
        col = [i for i in range(1,13)]
        row = np.asarray(['A','B','C','D','E','F','G','H'])
        filler = np.array(['-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-',]).reshape((8,2))


Ovennævnte kode skaber arrayer, der skal stables med den oprindelige matrix. 'Filler' -arrangementet er placeret baseret på brugerindtastningen af ​​'højre' eller 'venstre' ( stablingskommandoen, np.c\_ [[]], ses under ).


        #Create output
        Outfile = open('Total\_DNA\_{0}'.format(InfileName),"w")
        Outfile.write("DNA concentration (ng/uL):

")
        Outfile.write("	"+"	".join([str(n) for n in col])+"
")
        if orientation == "left": #Add filler to left, then add row to the left of filler
            ng\_per\_microliter = np.c\_[filler,ng\_per\_microliter]
            ng\_per\_microliter = np.c\_[row,ng\_per\_microliter]
            Outfile.write("
".join(["	".join([n for n in item]) for item in ng\_per\_microliter.tolist()])+"

")
        elif orientation == "right": #Add rows to the left, and filler to the right
            ng\_per\_microliter = np.c\_[row,ng\_per\_microliter]
            ng\_per\_microliter = np.c\_[ng\_per\_microliter,filler]
            Outfile.write("
".join(["	".join([n for n in item]) for item in ng\_per\_microliter.tolist()])+"

")
        Outfile.write("Total mass of DNA per sample (ng):

")
        Outfile.write("	"+"	".join([str(n) for n in col])+"
")
        if orientation == "left":
            ng\_total = np.c\_[filler,ng\_total]
            ng\_total = np.c\_[row,ng\_total]
            Outfile.write("
".join(["	".join([n for n in item]) for item in ng\_total.tolist()]))
        elif orientation == "right":
            ng\_total = np.c\_[row,ng\_total]
            ng\_total = np.c\_[ng\_total,filler]
            Outfile.write("
".join(["	".join([n for n in item]) for item in ng\_total.tolist()]))
        Outfile.close


Endelig har vi generationen af ​​outputfilen. Det er her den problematiske adfærd opstår.


Ved hjælp af en simpel udskrivningskommando fandt jeg, at stablingskommandoen numpy.c\_ [[]] er synderen (IKKE array skriftkommandoen).


Så det ser ud til, at numpy.c\_ [[]] ikke afkorter disse tal i Windows, men begrænser disse tal til det første tegn i et UNIX-miljø.


Hvad er nogle alternativer, der kan arbejde på begge platforme? Hvis intet eksisterer, er det ikke noget, jeg laver et UNIX-specifikt script.


Mange tak for din hjælp og din tålmodighed. Undskyld for ikke at give alle de nødvendige oplysninger tidligere.


Billederne er skærmbilleder, der viser korrekt output fra Windows, og hvad jeg ender med at komme i UNIX (jeg forsøgte at formatere disse til dig ... men de var et mareridt). Jeg har også inkluderet et skærmbillede af output opnået i terminalen, når jeg blot udskriver arraysne 'ng\_per\_microliter' og 'ng\_total.' Forventet output
UNIX Output
Trykte Arrays (UNIX Terminal) [16] [17] [18]

Bedste reference



  Ved hjælp af en simpel udskrivningskommando fandt jeg, at stablingskommandoen numpy.c\_ [[]] er synderen (IKKE array skriftkommandoen).

  
  Så det ser ud til at numpy.c\_ [[]] ikke afkorter disse tal i Windows, men vil begrænse disse tal til det første tegn i et UNIX-miljø.



Illustrer disse udsagn i enkle eksempler. np.c\_[] bør ikke gøre noget anderledes.


I Py3, hvor standardstrengen skriver i unicode. Og numpy 1.12


In [149]: col = [i for i in range(1,13)]
     ...: row = np.asarray(['A','B','C','D','E','F','G','H'])
     ...: filler = np.array(['-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-',]).reshape((8,2))
     ...: 
In [150]: col
Out[150]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
In [151]: "	"+"	".join([str(n) for n in col])+"
"
Out[151]: '	1	2	3	4	5	6	7	8	9	10	11	12
'
In [152]: filler
Out[152]: 
array([**'-', '-'],
       ...
       ['-', '-'],
       ['-', '-'**], 
      dtype='<U1')
In [153]: row
Out[153]: 
array(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'], 
      dtype='<U1')
In [154]: row.shape
Out[154]: (8,)
In [155]: filler.shape
Out[155]: (8, 2)
In [159]: ng\_per\_microliter=np.arange(8.)+1.23
In [160]: np.c\_[filler,ng\_per\_microliter]
Out[160]: 
array([**'-', '-', '1.23'],
       ['-', '-', '2.23'],
       ['-', '-', '3.23'],
      ...
       ['-', '-', '8.23'**], 
      dtype='<U32')
In [161]: np.c\_[row,ng\_per\_microliter]
Out[161]: 
array([**'A', '1.23'],
       ['B', '2.23'],
       ['C', '3.23'],
         ....
       ['H', '8.23'**], 
      dtype='<U32')


Det er muligt, at med tidligere numpy versioner, at en konkatenat af U1 (eller S1 i Py2) array med numeriske værdier forlader dtype på U1. I mit eksempel er de blevet udvidet til U32.


Så hvis du har mistanke om np.c\_, vis resultatet af dem (med repr, hvis det er nødvendigt)


print(repr(np.c\_[row,ng\_per\_microliter]))


og spor dtype.


for v 1.12 udgivelsesnotater (muligvis tidligere)



  Astype-metoden returnerer nu en fejl, hvis strengen dtype, der skal kastes til, ikke er lang nok i 'sikker' casting-tilstand for at holde den maksimale værdi af heltal/float array, der bliver kastet. Tidligere blev støbningen tilladt, selvom resultatet blev afkortet.



Dette kan komme i spil, når du laver sammen.

Andre referencer 1


Ved hjælp af brugeren har jeg fundet ud af, at dette ikke er et problem med forskellige adfærd mellem operativsystemer og miljøer. Det er mere end sandsynligt på grund af at brugere har forskellige versioner af numpy.


Sammenkoblingen af ​​arrayer konverterede automatisk 'float64' dtypes til 'S1' (for at matche 'filler' arrayerne ('-') og 'row' arrayerne ('A', 'B' osv.)).


Nyere versioner af numpy - specifikt v 1.12.X - synes at tillade sammenkædning af arrayer uden denne automatiske konvertering.


Jeg er stadig ikke sikker på en vej rundt om dette problem i ældre versioner af numpy, men det bør være et simpelt spørgsmål at rådgive folk til at opgradere deres version for fuld ydeevne. :)