2013-08-03 150 views
1

經過多次嘗試,我開始將我的R腳本遷移到Python。我在R中的大部分工作都涉及數據框架,而我正在使用pandas軟件包中的DataFrame對象。在我的腳本中,我需要讀取一個csv文件並將數據導入到一個DataFrame對象中。接下來,我需要將十六進制值轉換爲標記爲DATA的列,轉換爲按位數據,然後創建16個新列,每位一個。如何將數據幀列拆分爲多列

我的示例性輸入數據在文件test.txt如下所示,

PREFIX,TEST,ZONE,ROW,COL,DATA

6_6,READ,0,0,0,BFED

6_6,READ,0,1,0,BB7D

6_6,READ,0,2,0,FFF7

6_6,READ,0,3,0,E7FF

6_6,READ,0,4,0,FBF8

6_6,READ,0,5,0,DE75

6_6,READ,0,6,0,DFFE

我的python腳本test.py如下所示,

import glob 

import pandas as pd 

import numpy as np 

fname = 'test.txt' 

df = pd.read_csv(fname, comment="#") 

dfs = df[df.TEST == 'READ'] 

# function to convert the hexstring into a binary string 

def hex2bin(hstr): 

    return bin(int(hstr,16))[2:] 


# convert the hexstring in column DATA to binarystring ROWDATA 

dfs['BINDATA'] = dfs['DATA'].apply(hex2bin) 

# get rid of the column DATA 

del dfs['DATA'] 

當我運行此腳本,並檢查對象dfs,我得到以下,

PREFIX測試區ROW COL BINDATA

0 6_6 READ 0 0 0 1011111111101101

1 6_6 READ 0 1 0 1011101101111101

2 6_6 READ 0 2 0 1111111111110111

3 6_6閱讀0 3 0 1110011111111111

4 6_6閱讀0 4 0 1111101111111000

5 6_6閱讀0 5 0 1101111001110101

6 6_6閱讀0 6 0 1101111111111110

所以,現在我不知道如何進行拆分的列命名爲BINDATA分爲16個新列(可以命名爲B0,B0,B2,...,B15)。任何幫助將不勝感激。

感謝&問候,

Derric。

+0

你在試圖拆分'BINDATA'列時想到了什麼? –

回答

4

我不知道這是可以做到簡單(無需for循環),但是這確實的伎倆:

for i in range(16): 
    dfs['B'+str(i)] = dfs['BINDATA'].str[i] 

系列的str屬性可以訪問一些量化的字符串方法,其作用在每個元素上(參見文檔:http://pandas.pydata.org/pandas-docs/stable/basics.html#vectorized-string-methods)。在這種情況下,我們只是索引字符串以訪問不同的字符。
這給了我:

In [20]: dfs 
Out[20]: 
      BINDATA B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 
0 1011111111101101 1 0 1 1 1 1 1 1 1 1 1 0 1 1 0 1 
1 1011101101111101 1 0 1 1 1 0 1 1 0 1 1 1 1 1 0 1 
2 1111111111110111 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 
3 1110011111111111 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 
4 1111101111111000 1 1 1 1 1 0 1 1 1 1 1 1 1 0 0 0 
5 1101111001110101 1 1 0 1 1 1 1 0 0 1 1 1 0 1 0 1 
6 1101111111111110 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 

如果你希望他們爲整數,而不是字符串,可以在for循環添加.astype(int)


編輯:另一種方式來做到這一點(一oneliner,但你必須改變在第二步中的列名):

In [34]: splitted = dfs['BINDATA'].apply(lambda x: pd.Series(list(x))) 

In [35]: splitted.columns = ['B'+str(x) for x in splitted.columns] 

In [36]: dfs.join(splitted) 
Out[36]: 
      BINDATA B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 
0 1011111111101101 1 0 1 1 1 1 1 1 1 1 1 0 1 1 0 1 
1 1011101101111101 1 0 1 1 1 0 1 1 0 1 1 1 1 1 0 1 
2 1111111111110111 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 
3 1110011111111111 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 
4 1111101111111000 1 1 1 1 1 0 1 1 1 1 1 1 1 0 0 0 
5 1101111001110101 1 1 0 1 1 1 1 0 0 1 1 1 0 1 0 1 
6 1101111111111110 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 
+0

pd.Series從BINDATA的每一行/元素創建一個序列。 「分裂」如何變成數據框的邏輯是什麼?謝謝。 – julieth

+0

如果應用的函數返回一個DataFrame,則系列上的'apply'返回一個Series的每個元素,其中返回的Series的不同元素將成爲一行不同列的值。因此,在這種情況下,首先'list'函數將BINDATA中的字符串轉換爲一個列表,然後轉換爲一個列表(另請參閱@cpcloud的答案,它實際上是相同的,但寫法有些不同) – joris

+0

感謝!這就說得通了。 – julieth

1

這裏是你如何能做到這一點沒有一個循環(但不是真的,因爲在這個代碼中有很多隱式循環):

import pandas as pd 

# read the above frame from the clipboard 
df = pd.read_clipboard(converters={'BINDATA': str}) 
df = df.fillna(nan).replace('None', nan).dropna(axis=0, how='all') 

# here are the lines that matter 
bindata = df.BINDATA.apply(list).apply(Series) 
bindata.columns = bindata.columns.map('B{0}'.format) 
res = pd.concat([df, bindata], axis=1).convert_objects(convert_numeric=True)