因此。我们有一个凌乱数据存储在我需要分析的TSV文件中。 这就是它的外观
status=200 protocol=http region_name=Podolsk datetime=2016-03-10 15:51:58 user_ip=0.120.81.243 user_agent=Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36 user_id=7885299833141807155 user_vhost=tindex.ru method=GET page=/search/
问题是有些行有不同的列顺序/其中一些缺少值,我需要摆脱高性能(因为我使用的数据集高达100千兆字节)。
Data = pd.read_table('data/data.tsv', sep='\t+',header=None,names=['status', 'protocol',\
'region_name', 'datetime',\
'user_ip', 'user_agent',\
'user_id', 'user_vhost',\
'method', 'page'], engine='python')
Clean_Data = (Data.dropna()).reset_index(drop=True)
正如您所看到的,有些列是偏移的。 我制作了一个非常低性能的解决方案
ids = Clean_Data.index.tolist()
for column in Clean_Data.columns:
for row, i in zip(Clean_Data[column], ids):
if np.logical_not(str(column) in row):
Clean_Data.drop([i], inplace=True)
ids.remove(i)
所以现在数据看起来不错......至少我可以使用它! 但是我上面提到的方法的高性能替代方案是什么?
unutbu代码更新:追溯错误
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-4-52c9d76f9744> in <module>()
8 df.index.names = ['index', 'num']
9
---> 10 df = df.set_index('field', append=True)
11 df.index = df.index.droplevel(level='num')
12 df = df['value'].unstack(level=1)
/Users/Peter/anaconda/lib/python2.7/site-packages/pandas/core/frame.pyc in set_index(self, keys, drop, append, inplace, verify_integrity)
2805 if isinstance(self.index, MultiIndex):
2806 for i in range(self.index.nlevels):
-> 2807 arrays.append(self.index.get_level_values(i))
2808 else:
2809 arrays.append(self.index)
/Users/Peter/anaconda/lib/python2.7/site-packages/pandas/indexes/multi.pyc in get_level_values(self, level)
664 values = _simple_new(filled, self.names[num],
665 freq=getattr(unique, 'freq', None),
--> 666 tz=getattr(unique, 'tz', None))
667 return values
668
/Users/Peter/anaconda/lib/python2.7/site-packages/pandas/indexes/range.pyc in _simple_new(cls, start, stop, step, name, dtype, **kwargs)
124 return RangeIndex(start, stop, step, name=name, **kwargs)
125 except TypeError:
--> 126 return Index(start, stop, step, name=name, **kwargs)
127
128 result._start = start
/Users/Peter/anaconda/lib/python2.7/site-packages/pandas/indexes/base.pyc in __new__(cls, data, dtype, copy, name, fastpath, tupleize_cols, **kwargs)
212 if issubclass(data.dtype.type, np.integer):
213 from .numeric import Int64Index
--> 214 return Int64Index(data, copy=copy, dtype=dtype, name=name)
215 elif issubclass(data.dtype.type, np.floating):
216 from .numeric import Float64Index
/Users/Peter/anaconda/lib/python2.7/site-packages/pandas/indexes/numeric.pyc in __new__(cls, data, dtype, copy, name, fastpath, **kwargs)
105 # with a platform int
106 if (dtype is None or
--> 107 not issubclass(np.dtype(dtype).type, np.integer)):
108 dtype = np.int64
109
TypeError: data type "index" not understood
熊猫版:0.18.0-np110py27_0
更新
一切正常......谢谢大家!
答案 0 :(得分:5)
假设您有TSV数据,例如:
status=A protocol=B region_name=C datetime=D user_ip=E user_agent=F user_id=G
user_id=G status=A region_name=C user_ip=E datetime=D user_agent=F protocol=B
protocol=B datetime=D status=A user_ip=E user_agent=F user_id=G
字段的顺序可能被篡改,并且可能存在缺失值。但是,您不必因为字段不按特定顺序显示而丢弃行。您可以使用行数据本身提供的字段名称将值放在正确的列中。例如,
import pandas as pd
df = pd.read_table('data/data.tsv', sep='\t+',header=None, engine='python')
df = df.stack().str.extract(r'([^=]*)=(.*)', expand=True).dropna(axis=0)
df.columns = ['field', 'value']
df = df.set_index('field', append=True)
df.index = df.index.droplevel(level=1)
df = df['value'].unstack(level=1)
print(df)
产量
field datetime protocol region_name status user_agent user_id user_ip
index
0 D B C A F G E
1 D B C A F G E
2 D B None A F G E
要处理大型TSV文件,您可以处理块中的行,然后将处理后的块连接到最后的一个DataFrame中:
import pandas as pd
chunksize = # the number of rows to be processed per iteration
dfs = []
reader = pd.read_table('data/data.tsv', sep='\t+',header=None, engine='python',
iterator=True, chunksize=chunksize)
for df in reader:
df = df.stack().str.extract(r'([^=]*)=(.*)', expand=True).dropna(axis=0)
df.columns = ['field', 'value']
df.index.names = ['index', 'num']
df = df.set_index('field', append=True)
df.index = df.index.droplevel(level='num')
df = df['value'].unstack(level=1)
dfs.append(df)
df = pd.concat(dfs, ignore_index=True)
print(df)
说明:给定df
:
In [527]: df = pd.DataFrame({0: ['status=A', 'user_id=G', 'protocol=B'],
1: ['protocol=B', 'status=A', 'datetime=D'],
2: ['region_name=C', 'region_name=C', 'status=A'],
3: ['datetime=D', 'user_ip=E', 'user_ip=E'],
4: ['user_ip=E', 'datetime=D', 'user_agent=F'],
5: ['user_agent=F', 'user_agent=F', 'user_id=G'],
6: ['user_id=G', 'protocol=B', None]}); df
.....: .....: .....: .....: .....: .....: .....:
Out[527]:
0 1 2 3 4 5 6
0 status=A protocol=B region_name=C datetime=D user_ip=E user_agent=F user_id=G
1 user_id=G status=A region_name=C user_ip=E datetime=D user_agent=F protocol=B
2 protocol=B datetime=D status=A user_ip=E user_agent=F user_id=G None
您可以将所有值合并为一列
In [449]: df.stack()
Out[449]:
0 0 status=A
1 protocol=B
2 region_name=C
3 datetime=D
4 user_ip=E
5 user_agent=F
6 user_id=G
1 0 user_id=G
1 status=A
2 region_name=C
3 user_ip=E
4 datetime=D
5 user_agent=F
6 protocol=B
2 0 protocol=B
1 datetime=D
2 status=A
3 user_ip=E
4 user_agent=F
5 user_id=G
dtype: object
然后应用.str.extract(r'([^=]*)=(.*)')
将字段名称与值分开:
In [450]: df = df.stack().str.extract(r'([^=]*)=(.*)', expand=True).dropna(axis=0); df
Out[450]:
0 1
0 0 status A
1 protocol B
2 region_name C
3 datetime D
4 user_ip E
5 user_agent F
6 user_id G
1 0 user_id G
1 status A
2 region_name C
3 user_ip E
4 datetime D
5 user_agent F
6 protocol B
2 0 protocol B
1 datetime D
2 status A
3 user_ip E
4 user_agent F
5 user_id G
为了更容易引用DataFrame的部分内容,让我们为列和索引级别提供描述性名称:
In [530]: df.columns = ['field', 'value']; df.index.names = ['index', 'num']; df
Out[530]:
field value
index num
0 0 status A
1 protocol B
...
现在,如果我们将field
列移动到索引中:
In [531]: df = df.set_index('field', append=True); df
Out[531]:
value
index num field
0 0 status A
1 protocol B
2 region_name C
3 datetime D
...
并删除num
索引级别:
In [532]: df.index = df.index.droplevel(level='num'); df
Out[532]:
value
index field
0 status A
protocol B
region_name C
datetime D
...
然后我们可以获得所需形式的DataFrame
将field
索引级别移动到列索引中:
In [533]: df = df['value'].unstack(level=1); df
Out[533]:
field datetime protocol region_name status user_agent user_id user_ip
index
0 D B C A F G E
1 D B C A F G E
2 D B None A F G E
答案 1 :(得分:4)
你可以使用熊猫&#39; vectorized string operations,具体为str.contains
:
import numpy as np
# boolean index of rows to keep
is_valid = np.ones(Clean_data.shape[0], np.bool)
for column in Clean_Data.columns:
# check whether rows contain this column name
is_valid &= Clean_Data[column].str.contains(column)
# drop rows where not all elements contain their respective column names
Clean_Data.drop(np.where(~is_valid)[0], inplace=True)
答案 2 :(得分:3)
我无法添加评论,因此我会将此作为回复发布(实际上,这是对您对内存使用情况和运行时的评论的回复)。
对于大文件(100GB),您需要考虑的一件事是您不会将这些文件读入内存。您可以为pandas “Large data” work flows using pandas或How to read a 6 GB csv file with pandas设置块大小,或者将yield generator与csv模块一起使用,并逐行读取文件行。 Reading a huge .csv in python
结合@ unutbu关于使用正则表达式将条目排序到列中的注释,假设字段名为每个单元格划分得很明确(即r'(.*)=(.*)'
只需要所有 - 尽管可能需要进行一些纠错)应该是你需要的所有东西(正如他们所说,由于一些缺失的数据而丢弃整行,这不是典型的或推荐的方法)。