How to preprocess and load a “big data” tsv file into a python dataframe?

后端 未结 3 1007
谎友^
谎友^ 2020-12-06 23:00

I am currently trying to import the following large tab-delimited file into a dataframe-like structure within Python---naturally I am using pandas dataframe, th

相关标签:
3条回答
  • 2020-12-06 23:18

    You can do this more cleanly completely in Pandas.

    Suppose you have two independent data frames with only one overlapping column:

    >>> df1
       A  B
    0  1  2
    >>> df2
       B  C
    1  3  4
    

    You can use .concat to concatenate them together:

    >>> pd.concat([df1, df2])
        A  B   C
    0   1  2 NaN
    1 NaN  3   4
    

    You can see NaN is created for row values that do not exist.

    This can easily be applied to your example data without preprocessing at all:

    import pandas as pd
    df=pd.DataFrame()
    with open(fn) as f_in:
        for i, line in enumerate(f_in):
            line_data=pd.DataFrame({k.strip():v.strip() 
                      for k,_,v in (e.partition(':') 
                            for e in line.split('\t'))}, index=[i])
            df=pd.concat([df, line_data])
    
    >>> df
      Col_01 Col_20 Col_21  Col_22  Col_23 Col_24  Col_25
    0     14     25  23432  639142     NaN    NaN     NaN
    1      8     25    NaN   25134  243344    NaN     NaN
    2     17    NaN     75       5   79876  73453  634534
    3     19     25  32425     NaN  989423    NaN     NaN
    4     12     25  23424  342421       7  13424      67
    5      3     95  32121     NaN     NaN    NaN  111231
    

    Alternatively, if your main issue is establishing the desired order of the columns in a multi chunk add of columns, just read all the column value first (not tested):

    # based on the alpha numeric sort of the example of:
    # [ALPHA]_[NUM]
    headers=set()
    with open(fn) as f:
        for line in f:
            for record in line.split('\t'):
                head,_,datum=record.partition(":")
                headers.add(head)
    # sort as you wish:             
    cols=sorted(headers, key=lambda e: int(e.partition('_')[2])) 
    

    Pandas will use the order of the list for the column order if given in the initial creation of the DataFrame.

    0 讨论(0)
  • 2020-12-06 23:24
    $ cat > pandas.awk
    BEGIN {
        PROCINFO["sorted_in"]="@ind_str_asc" # traversal order for for(i in a)                  
    }
    NR==1 {       # the header cols is in the beginning of data file
                  # FORGET THIS: header cols from another file replace NR==1 with NR==FNR and see * below
        split($0,a," ")                  # mkheader a[1]=first_col ...
        for(i in a) {                    # replace with a[first_col]="" ...
            a[a[i]]
            printf "%6s%s", a[i], OFS    # output the header
            delete a[i]                  # remove a[1], a[2], ...
        }
        # next                           # FORGET THIS * next here if cols from another file UNTESTED
    }
    {
        gsub(/: /,"=")                   # replace key-value separator ": " with "="
        split($0,b,FS)                   # split record from ","
        for(i in b) {
            split(b[i],c,"=")            # split key=value to c[1]=key, c[2]=value
            b[c[1]]=c[2]                 # b[key]=value
        }
        for(i in a)                      # go thru headers in a[] and printf from b[]
            printf "%6s%s", (i in b?b[i]:"NaN"), OFS; print ""
    }
    

    Data sample (pandas.txt):

    Col_01 Col_20 Col_21 Col_22 Col_23 Col_25
    Col_01: 14  Col_20: 25    Col_21: 23432    Col_22: 639142
    Col_01: 8   Col_20: 25    Col_22: 25134    Col_23: 243344
    Col_01: 17  Col_21: 75    Col_23: 79876    Col_25: 634534    Col_22: 5    Col_24: 73453
    Col_01: 19  Col_20: 25    Col_21: 32425    Col_23: 989423
    Col_01: 12  Col_20: 25    Col_21: 23424    Col_22: 342421    Col_23: 7    Col_24: 13424    Col_25: 67
    Col_01: 3   Col_20: 95    Col_21: 32121    Col_25: 111231
    
    $ awk -f pandas.awk -pandas.txt
    Col_01 Col_20 Col_21 Col_22 Col_23 Col_25
        14     25  23432 639142    NaN    NaN 
         8     25    NaN  25134 243344    NaN 
        17    NaN     75      5  79876 634534 
        19     25  32425    NaN 989423    NaN 
        12     25  23424 342421      7     67 
         3     95  32121    NaN    NaN 111231 
    

    All needed cols should be in the data file header. It's probably not a big job to collect the headers while processing, just keep the data in arrays and print in the end, maybe in version 3.

    If you read the headers from a different file (cols.txt) than the data file (pandas.txt), execute the script (pandas.awk):

    $ awk -F pandas.awk cols.txt pandas.txt
    
    0 讨论(0)
  • 2020-12-06 23:28

    Another version which takes a separate column file as parameter or uses the first record. Run either way:

    awk -f pandas2.awk pandas.txt # first record as header
    awk -f pandas2.awk cols.txt pandas.txt # first record from cols.txt
    awk -v cols="cols.txt" -f pandas2.awk pandas.txt # read cols from cols.txt
    

    Or even:

    awk -v cols="pandas.txt" -f pandas2.awk pandas.txt # separates keys from pandas.txt for header
    

    Code:

    $ cat > pandas2.awk
    BEGIN {
        PROCINFO["sorted_in"]="@ind_str_asc" # traversal order for for(i in a)
        if(cols) {                           # if -v cols="column_file.txt" or even "pandas.txt"
            while ((getline line< cols)>0) { # read it in line by line
                gsub(/: [^ ]+/,"",line)      # remove values from "key: value"
                split(line,a)                # split to temp array
                for(i in a)                  # collect keys to column array
                    col[a[i]]
            }
            for(i in col)                    # output columns
                printf "%6s%s", i, OFS
            print ""
        }
    }
    NR==1 && cols=="" {                      # if the header cols are in the beginning of data file
                                             # if not, -v cols="column_file.txt"
        split($0,a," +")                     # split header record by spaces
        for(i in a) {
            col[a[i]]                        # set them to array col
            printf "%6s%s", a[i], OFS        # output the header
        }
        print ""
    }
    NR==1 {
        next
    }
    {
        gsub(/: /,"=")                       # replace key-value separator ": " with "="
        split($0,b,FS)                       # split record from separator FS
        for(i in b) {
            split(b[i],c,"=")                # split key=value to c[1]=key, c[2]=value
            b[c[1]]=c[2]                     # b[key]=value
        }
        for(i in col)                        # go thru headers in col[] and printf from b[]
            printf "%6s%s", (i in b?b[i]:"NaN"), OFS; print ""
    }
    
    0 讨论(0)
提交回复
热议问题