2016-04-14 22 views
2

有缺失數據的處理我有一個數據集,如:在一列文本文件

IM,XX 
IS,YY 
SG,3 
OTPL,90 
TTPL,90 
IM,AA 
IS,BB 
SG,3 
TTPL,50 
IM,ZZ 
IS,CC 
OTPL,10 

每一行包含key,value對,我需要將其轉換成表格的形式,以便進行一些分析。變量IM表示行的索引,下面的參數是列。對我來說,棘手的部分是考慮到可能缺失的值。預期的結果是:

IM IS OTPL SG TTPL 
XX YY 90  3 90  
AA BB null  3 50  
ZZ CC 10 null null 

「注意空值」。

我有一個解決方案,但沒有那麼高效,當數據集非常大時,它不是一個合適的方法。我用下面的策略:

  1. 隨着awk,添加一個額外的指數每個寄存器(行)。它創建了一個計數器n當出現IM增加它:

    $ awk -F, 'BEGIN{n = 0}{ if($1 == "IM"){n += 1} print n","$0}' inputdata.txt 
    1,IM,XX 
    1,IS,YY 
    1,SG,3 
    1,OTPL,90 
    1,TTPL,90 
    2,IM,AA 
    2,IS,BB 
    2,SG,3 
    2,TTPL,50 
    3,IM,ZZ 
    3,IS,CC 
    3,OTPL,10 
    
  2. 接下來,讀取使用pandas,應用由上述指標groupby先前的結果,並創建應用concatpivot子表的新表:

    In[1]:import pandas as pd 
         gb = pd.read_csv("outdata.txt", names = ["id","key","value"]).groupby("id") 
         res = pd.concat([df.pivot(index="id", columns='key', values='value') for g, df in gb]) 
         res 
    Out[1]: 
        IM IS OTPL SG TTPL 
    id      
    1 XX YY 90 3 90 
    2 AA BB NaN 3 50 
    3 ZZ CC 10 NaN NaN 
    

最後一步非常昂貴。

有沒有人有類似的問題?只有用命令行才能解決這個問題。

提前致謝!

+1

所以你的目標是做僅使用shell命令對這些數據的分析(即,「只使用命令行」)?我想這並不清楚爲什麼你的'熊貓'解決方案對你來說不夠好。你的數據集有多大? – dbliss

+0

我假設數據的順序非常重要,並且順序的改變可能會破壞結果。 – Alexander

+0

我認爲這必須是使用shell命令或其他工具的更高效方式。當我如上所述使用'pandas'時,這個操作需要大約10秒鐘的時間,只有1000行的數據集(在普通的臺式計算機中)也消耗大量內存。 –

回答

2

[更新]純GAWK解決方案:

BEGIN { 
    FS=OFS="," 
    n = 0 
} 
{ 
    if($1 == "IM") { 
     n++ 
    } 
    keys[$1]++ 
    vals[n,$1]=$2 
} 
END { 
    l=asorti(keys, copy) 
    printf "id" 
    for (i=1; i<=l; i++) { 
     printf "%s%s", FS, copy[i] 
    } 
    print "" 

    for (i=1; i<=n; i++) { 
     printf "%s", i 
     for (k=1; k<=l; k++) { 
      printf "%s%s", FS, vals[i,copy[k]] 
     } 
     print "" 
    } 
} 

輸出:

{ .data } » awk -f prg.awk data.csv 
id,IM,IS,OTPL,SG,TTPL 
1,XX,YY,90,3,90 
2,AA,BB,,3,50 
3,ZZ,CC,10,, 

[老]熊貓的解決方案:

我想你可以只使用pivot_table()代替groupby() + concat()

In [105]: df 
Out[105]: 
    id key val 
0 1 IM XX 
1 1 IS YY 
2 1 SG 3 
3 1 OTPL 90 
4 1 TTPL 90 
5 2 IM AA 
6 2 IS BB 
7 2 SG 3 
8 2 TTPL 50 
9 3 IM ZZ 
10 3 IS CC 
11 3 OTPL 10 

In [106]: df.pivot_table(index='id', columns='key', values='val', aggfunc='sum', fill_value=np.nan) 
Out[106]: 
key IM IS OTPL SG TTPL 
id 
1 XX YY 90 3 90 
2 AA BB NaN 3 50 
3 ZZ CC 10 NaN NaN 

pivot()如果你沒有重複的(如在您的樣本數據集):

In [109]: df.pivot(index='id', columns='key', values='val') 
Out[109]: 
key IM IS OTPL SG TTPL 
id 
1 XX YY 90  3 90 
2 AA BB None  3 50 
3 ZZ CC 10 None None 

NaN!而非None S也是一樣的:

In [110]: df.pivot(index='id', columns='key', values='val').fillna(np.nan) 
Out[110]: 
key IM IS OTPL SG TTPL 
id 
1 XX YY 90 3 90 
2 AA BB NaN 3 50 
3 ZZ CC 10 NaN NaN 
+0

優秀的解決方案。它大大縮短了執行時間! :-)。在這種情況下'aggfunc'不是必需的,因爲每個'id'都有唯一的'key'。非常感謝! –

+0

@ej_f,總是很樂意幫忙。我已經添加了一個AWK解決方案 - 請你檢查一下,並給出一個簡短的反饋 - 哪一個更快? – MaxU

+1

@ej_f如果上述答案解決了您的問題(看起來是這種情況),請務必單擊答案旁邊的複選標記,將問題標記爲已解決。 – beroe

1
def my_transform(infile, outfile): 
    df = pd.read_csv(infile, header=None, sep=",", names=['id', None]) 
    df = df.groupby([(df.id == 'IM').cumsum(), 'id']).first().unstack() 
    df.columns = df.columns.droplevel() 
    df.to_csv(outfile, index=None) 

infile = "..." 
outfile = "..." 
my_transform(infile, outfile) 

>>> !cat "..." # outfile 
IM,IS,OTPL,SG,TTPL 
XX,YY,90,3,90 
AA,BB,,3,50 
ZZ,CC,10,, 

groupby的關鍵是在(df.id == 'IM').cumsum()上分組,這意味着發生第一列中的'即時消息'的描述描繪了一個新的羣體。 my_transform函數獲取輸入文件,將其轉換爲所需的輸出,然後將結果保存迴文件。

df['group'] = (df.id == 'IM').cumsum() 
>>> df 
     id NaN group 
0  IM XX  0 
1  IS YY  0 
2  SG 3  0 
3 OTPL 90  0 
4 TTPL 90  0 
5  IM AA  1 
6  IS BB  1 
7  SG 3  1 
8 TTPL 50  1 
9  IM ZZ  2 
10 IS CC  2 
11 OTPL 10  2 
+0

謝謝@亞歷山大,絕對是一位熊貓大師!你的想法真棒!下面的文章顯示瞭解決方案的執行時間。 –

1

非常感謝@Alexander和@MaxU的評論。

awk純溶液的性能略好於pandas。 以下結果用35500行的數據集獲得的:

# initial solution (pandas + awk) 
In [2]: %timeit ej_f_pandas() 
1 loops, best of 3: 1min 14s per loop 

# maxu's solution (pandas + awk) 
In [3]: %timeit maxu_pandas() 
1 loops, best of 3: 697 ms per loop 

# alexander's solution (pandas) 
In [4]: %timeit alexander_pandas() 
1 loops, best of 3: 518 ms per loop 

# maxu's solution (awk) 
In [5]: %timeit maxu_awk() 
1 loops, best of 3: 499 ms per loop 
+2

謝謝比較 - 比較不同的解決方案/方法總是很有趣 – MaxU