Python Pandas 根据条目的字符串值过滤行
Python Pandas filter rows based on the string value of an entry
我有一个 excel sheet(Bloomberg 数据许可证输出),我用
阅读
import pandas as pd
raw_data = pd.read_excel('my-file.xlsx')
只有一列 (START-OF-FILE
) 和不同数量的行,具体取决于返回的数据量。
我对两行之间的数据感兴趣,特别是 START-OF-DATA
和 END-OF-DATA
。该列中的行看起来像
19 START-OF-DATA
20 WTS Equity|0|6|WTS|50545|54.440000|54.000000|5...
21 XOM Equity|0|6|XOM|6555175|84.950000|85.300000...
22 SUP Equity|0|6|SUP|27405|19.250000|19.200000|1...
23 END-OF-DATA
行数不同(不总是 20 到 22)。如何将列中的行过滤为仅单元格之间的数据,即 raw_data['START-OF-FILE']['START-OF-DATA' : 'END-OF-DATA']
。然后使用 str.split('|')
将管道分隔的数据分隔到新数据帧的单独列中?
我写了一个函数来为你做这个:
def select_data(data, column, start, stop):
store = []
for idx, item in enumerate(data[column]):
if item in [start, stop]:
store.append(idx)
output = pd.DataFrame(list(data[column][store[0]+1:store[1]].str.split('|')))
return output
输出:
In [231]: df = pd.DataFrame(['a|b|c|d']*20, columns=['test-col']);
In [232]: df.ix[5, ['test-col']] = 'START'
In [233]: df.ix[17, ['test-col']] = 'STOP'
In [234]: df
Out[234]:
test-col
0 a|b|c|d
1 a|b|c|d
2 a|b|c|d
3 a|b|c|d
4 a|b|c|d
5 START
6 a|b|c|d
7 a|b|c|d
8 a|b|c|d
9 a|b|c|d
10 a|b|c|d
11 a|b|c|d
12 a|b|c|d
13 a|b|c|d
14 a|b|c|d
15 a|b|c|d
16 a|b|c|d
17 STOP
18 a|b|c|d
19 a|b|c|d
In [235]: test = filter_data(df, 'test-col', 'START','STOP')
In [236]: test
Out[236]:
0 1 2 3
0 a b c d
1 a b c d
2 a b c d
3 a b c d
4 a b c d
5 a b c d
6 a b c d
7 a b c d
8 a b c d
9 a b c d
10 a b c d
为了跟进这里,我 运行 对这两个功能进行了一些时间测试。以下是结果:
In [1]: import pandas as pd
In [2]: import timeit
In [3]: df = pd.DataFrame(['a|b|c|d']*10000, columns=['test-col'])
In [4]: df.ix[2654, ['test-col']] = 'START'
In [5]: df.ix[9000, ['test-col']] = 'STOP'
In [6]: %paste
def func_1(data, column, start, stop):
store = []
for idx, item in enumerate(data[column]):
if item in [start, stop]:
store.append(idx)
output = pd.DataFrame(list(data[column][store[0]+1:store[1]].str.split('|')))
return output
def func_2(df):
start, end = df[df['test-col'].str.contains('START|STOP')].index.tolist()
output = pd.DataFrame(df[start+1:end]['test-col'].str.split('|').tolist())
return output
## -- End pasted text --
In [7]: %timeit func_1(df, 'test-col', 'START','STOP')
100 loops, best of 3: 8.95 ms per loop
In [8]: %timeit func_2(df)
100 loops, best of 3: 13.3 ms per loop
我假设 func_1()
比 func_2()
快是因为 .contains()
方法使用正则表达式进行模式匹配。
>>> import pandas as pd
>>> df = pd.DataFrame(['abcdef', 'START-OF-DATA', 'g|h|i', 'j|k|l', 'm|n|o', 'END-OF-DATA', 'pqrstu', columns=['A']])
>>> df
A
0 abcdef
1 START-OF-DATA
2 g|h|i
3 j|k|l
4 m|n|o
5 END-OF-DATA
6 pqrstu
>>> start, end = df[df['A'].str.contains('(START|END)-OF-DATA')].index.tolist()
>>> pd.DataFrame(df[start+1:end]['A'].str.split('|').tolist(), columns=['A', 'B', 'C'])
A B C
2 g h i
3 j k l
4 m n o
我有一个 excel sheet(Bloomberg 数据许可证输出),我用
阅读import pandas as pd
raw_data = pd.read_excel('my-file.xlsx')
只有一列 (START-OF-FILE
) 和不同数量的行,具体取决于返回的数据量。
我对两行之间的数据感兴趣,特别是 START-OF-DATA
和 END-OF-DATA
。该列中的行看起来像
19 START-OF-DATA
20 WTS Equity|0|6|WTS|50545|54.440000|54.000000|5...
21 XOM Equity|0|6|XOM|6555175|84.950000|85.300000...
22 SUP Equity|0|6|SUP|27405|19.250000|19.200000|1...
23 END-OF-DATA
行数不同(不总是 20 到 22)。如何将列中的行过滤为仅单元格之间的数据,即 raw_data['START-OF-FILE']['START-OF-DATA' : 'END-OF-DATA']
。然后使用 str.split('|')
将管道分隔的数据分隔到新数据帧的单独列中?
我写了一个函数来为你做这个:
def select_data(data, column, start, stop):
store = []
for idx, item in enumerate(data[column]):
if item in [start, stop]:
store.append(idx)
output = pd.DataFrame(list(data[column][store[0]+1:store[1]].str.split('|')))
return output
输出:
In [231]: df = pd.DataFrame(['a|b|c|d']*20, columns=['test-col']);
In [232]: df.ix[5, ['test-col']] = 'START'
In [233]: df.ix[17, ['test-col']] = 'STOP'
In [234]: df
Out[234]:
test-col
0 a|b|c|d
1 a|b|c|d
2 a|b|c|d
3 a|b|c|d
4 a|b|c|d
5 START
6 a|b|c|d
7 a|b|c|d
8 a|b|c|d
9 a|b|c|d
10 a|b|c|d
11 a|b|c|d
12 a|b|c|d
13 a|b|c|d
14 a|b|c|d
15 a|b|c|d
16 a|b|c|d
17 STOP
18 a|b|c|d
19 a|b|c|d
In [235]: test = filter_data(df, 'test-col', 'START','STOP')
In [236]: test
Out[236]:
0 1 2 3
0 a b c d
1 a b c d
2 a b c d
3 a b c d
4 a b c d
5 a b c d
6 a b c d
7 a b c d
8 a b c d
9 a b c d
10 a b c d
为了跟进这里,我 运行 对这两个功能进行了一些时间测试。以下是结果:
In [1]: import pandas as pd
In [2]: import timeit
In [3]: df = pd.DataFrame(['a|b|c|d']*10000, columns=['test-col'])
In [4]: df.ix[2654, ['test-col']] = 'START'
In [5]: df.ix[9000, ['test-col']] = 'STOP'
In [6]: %paste
def func_1(data, column, start, stop):
store = []
for idx, item in enumerate(data[column]):
if item in [start, stop]:
store.append(idx)
output = pd.DataFrame(list(data[column][store[0]+1:store[1]].str.split('|')))
return output
def func_2(df):
start, end = df[df['test-col'].str.contains('START|STOP')].index.tolist()
output = pd.DataFrame(df[start+1:end]['test-col'].str.split('|').tolist())
return output
## -- End pasted text --
In [7]: %timeit func_1(df, 'test-col', 'START','STOP')
100 loops, best of 3: 8.95 ms per loop
In [8]: %timeit func_2(df)
100 loops, best of 3: 13.3 ms per loop
我假设 func_1()
比 func_2()
快是因为 .contains()
方法使用正则表达式进行模式匹配。
>>> import pandas as pd
>>> df = pd.DataFrame(['abcdef', 'START-OF-DATA', 'g|h|i', 'j|k|l', 'm|n|o', 'END-OF-DATA', 'pqrstu', columns=['A']])
>>> df
A
0 abcdef
1 START-OF-DATA
2 g|h|i
3 j|k|l
4 m|n|o
5 END-OF-DATA
6 pqrstu
>>> start, end = df[df['A'].str.contains('(START|END)-OF-DATA')].index.tolist()
>>> pd.DataFrame(df[start+1:end]['A'].str.split('|').tolist(), columns=['A', 'B', 'C'])
A B C
2 g h i
3 j k l
4 m n o