2017-02-12 70 views
3

我有这样的一个格式的文本文件:熊猫:在结构化非表格文本解析值

k1[a-token] 
v1 
v2 
k2[a-token] 
v1' 
k3[a-token] 
v1" 
v2" 
v3" 

什么是读取这些数据转换成这种形式的数据框最pandorable方式:

 A  B 
0  k1  v1 
1  k1  v2 
2  k2  v1' 
3  k3  v1" 
4  k3  v2" 
5  k3  v3" 

那不涉及手动循环?或者是否有任何其他库允许我只输入一些正则表达式来指定我的文本文件的结构并以上述表格形式输出数据?

+0

目前还不清楚您的格式是什么。你在每个组的开头是否在方括号中有一些标记,或者你的'[a-token]'是你在SO上放置的标记,以指示每个组的开始? – DSM

+0

耶的意思是说有一个模式表示键值的字符串结束。 – ShS

回答

3

设置
借款从@jezrael

import pandas as pd 
from pandas.compat import StringIO 

temp=u""" 
k1[a-token] 
v1 
v2 
k2[a-token] 
v1' 
k3[a-token] 
v1" 
v2" 
v3" 
""" 
#after testing replace 'StringIO(temp)' to 'filename.csv' 
df = pd.read_csv(StringIO(temp), sep="|", names=['B']) 
print (df) 

  • str.extract用正则表达式指定向前看
  • 使用duplicated,以确定我们要保持行参数。

df = df.B.str.extract('(?P<A>.*(?=\[a-token\]))?(?P<B>.*)', expand=True).ffill() 
df[df.duplicated(subset=['A'])].reset_index(drop=True) 

    A B 
0 k1 v1 
1 k1 v2 
2 k2 v1' 
3 k3 v1" 
4 k3 v2" 
5 k3 v3" 
1

您可以使用read_csv一些分离这是不是在数据像|¥:与extract值与[a-token]并与删除行上次使用boolean indexing与面具由duplicated

import pandas as pd 
from pandas.compat import StringIO 

temp=u""" 
k1[a-token] 
v1 
v2 
k2[a-token] 
v1' 
k3[a-token] 
v1" 
v2" 
v3" 
""" 
#after testing replace 'StringIO(temp)' to 'filename.csv' 
df = pd.read_csv(StringIO(temp), sep="|", names=['B']) 
print (df) 
      B 
0 k1[a-token] 
1   v1 
2   v2 
3 k2[a-token] 
4   v1' 
5 k3[a-token] 
6   v1" 
7   v2" 
8   v3" 

然后insert新列Akeys in values列:

df.insert(0, 'A', df['B'].str.extract('(.*)\[a-token\]', expand=False).ffill()) 
df = df[df['A'].duplicated()].reset_index(drop=True) 
print (df) 
    A B 
0 k1 v1 
1 k1 v2 
2 k2 v1' 
3 k3 v1" 
4 k3 v2" 
5 k3 v3" 

但是如果文件已经复制keys

print (df) 
       B 
0 k1[a-token] 
1   v1 
2   v2 
3 k2[a-token] 
4   v1' 
5 k3[a-token] 
6   v1" 
7   v2" 
8   v3" 
9 k2[a-token] 
10   v1' 

df.insert(0, 'A', df['B'].str.extract('(.*)\[a-token\]', expand=False).ffill()) 
df = df[df['A'].duplicated()].reset_index(drop=True) 
print (df) 
    A   B 
0 k1   v1 
1 k1   v2 
2 k2   v1' 
3 k3   v1" 
4 k3   v2" 
5 k3   v3" 
6 k2 k2[a-token] 
7 k2   v1' 

然后就是必要的改变mask

df.insert(0, 'A', df['B'].str.extract('(.*)\[a-token\]', expand=False).ffill()) 
df = df[~df['B'].str.contains('\[a-token]')].reset_index(drop=True) 
print (df) 
    A B 
0 k1 v1 
1 k1 v2 
2 k2 v1' 
3 k3 v1" 
4 k3 v2" 
5 k3 v3" 
6 k2 v1' 
0

有了您的文件为 'TEMP.TXT' ......

df = pd.read_csv('temp.txt', 
       header=None, 
       delim_whitespace=True, 
       names=['data']) 

bins = df.data.str.endswith('[a-token]') 

idx_bins = df[bins][:] 
idx_bins.data = idx_bins.data.str.rstrip(to_strip='[a-token]') 
idx_vals = df[~bins][:] 

a = pd.DataFrame(idx_bins.index.values, columns=['a']) 
b = pd.DataFrame(idx_vals.index.values, columns=['b']) 

merge_df = pd.merge_asof(b, a, left_on='b', right_on='a') 
new_df = pd.DataFrame({'A': idx_bins.data.loc[list(merge_df.a)].values, 
         'B': idx_vals.data.values}) 
+0

整个过程并没有在代码中出现任何可见的循环! :) – ShS

+0

对不起@ShS,我没有正确地读你的问题。在merge_asof替换循环后,这看起来如何? – b2002