使用python

时间:2017-05-17 08:11:58

标签: python csv pandas dictionary dataframe

我正在处理一个包含大约900行的特殊csv文件

0.0165824,+,ESI,ms1,-,line,40.0000-700.0000,663,35.2072 12,37.7808 11,38.0004 17,39.1216 18,39.1755 11,40.0806 12,41.4810 11,42.0517 19

值以逗号“,”分隔。但是,从第9列开始,该文件包含我实际感兴趣的元组值。我想使用pandas来完成这项工作。由于我使用这种方法的不同行的列数不相等:

import csv
import pandas as pd

with open('test.csv') as fb:
    reader = csv.reader(fb)
    df = pd.DataFrame().from_records(reader) 

这会产生一个包含元组作为字符串的数据框。从那时起,我首先计划使用第一列作为外部索引创建多索引数据帧,并使用每个元组值的内部索引(第9列向前)。或者作为替代,使用第一列作为键在字典中包含多个数据帧。

目前,我正在使用此代码:

import csv
import numpy as np

raw_data = 'test.csv'

result = {}
lower_mass = 200
upper_mass = 300

with open(raw_data, 'rb') as f:
    reader = csv.reader(f, delimiter=',')
    for row in reader:
        mz = []
        i = []
        key = float(row[0])
        data = row[8:]
        for d in data:
            tup = d.split(" ")
            mass = float(tup[0])
            intens = float(tup[1])
            if (mass > lower_mass) & (mass < upper_mass):
                mz.append(float(tup[0]))
                i.append(float(tup[1]))
        result[key] = {"mz": mz, "I": i}

这将生成一个字典,其中包含值mzI的两个列表,使用第一列作为键,为清楚起见,还删除了一些我不想存储的列(1-7)。我还应用过滤器来收缩数据(lower_mass和upper_mass)。这些操作本来是在数据框上进行的。

我不高兴,因为我失去了以矢量化方式进行数据处理的能力。最后,数据应该用于在不同的键中找到一些mz值。

是否有更好/更快的解决方案?

1 个答案:

答案 0 :(得分:1)

我想我明白你要做什么,如果不让我知道,我会编辑我的答案。

我接近这个的方法是在pandas中使用meltstr.split函数。融化将“宽”数据转换为“长”数据,这将允许您拆分元组并最终过滤数据。

使用此CSV文件,其中包含宽度不同的行以及从第8列开始的所有相关数据。

0.0165824,+,ESI,ms1,-,line,40.0000-700.0000,663,35.2072 12,37.7808 11,38.0004 17,39.1216 18,39.1755 11,40.0806 12,41.4810 11,42.0517 19
0.0165825,+,ESI,ms1,-,line,40.0000-700.0000,663,35.2072 12,37.7808 11,38.0004 17,39.1216 18,39.1755 11,40.0806 12,41.4810 11,42.0517 19,40.0806 12,41.4810 11,42.0517 19
0.0165826,+,ESI,ms1,-,line,40.0000-700.0000,663,35.2072 12,37.7808 11,38.0004 17,39.1216 18,39.1755 11

代码

import pandas as pd
import numpy as np

df = pd.read_csv('s.csv', header=None, names=np.arange(19)) # Read in CSV, use names to handle different CSV row widths
df = df.drop(np.arange(1,8), axis="columns") # Drop columns 1:7
df = pd.melt(df, id_vars=[0], value_vars=np.arange(8, df.shape[1])) # Melt data columns 8:N

# df.head()
#   0           variable    value
# 0 0.016582    8           35.2072 12
# 1 0.016583    8           35.2072 12
# 2 0.016583    8           35.2072 12
# 3 0.016582    9           37.7808 11
# 4 0.016583    9           37.7808 1

df[['mass','I']] = df.value.str.split(" ", expand=True).apply(pd.to_numeric, errors='coerce') # Split value column and apply change from string to numeric datatype; assign split to mass and I columns
df = df.rename(columns={0: "key", 'variable':'csv_column'}).drop('value', axis='columns') # Rename column zero to key and drop string column

# df.head()
#   key         csv_column  mass    I
#0  0.016582    8           35.2072 12
#1  0.016583    8           35.2072 12
#2  0.016583    8           35.2072 12
#3  0.016582    9           37.7808 11
#4  0.016583    9           37.7808 11

现在您可以使用pandas进行过滤和排序。请注意,CSV中的“空白”值将转换为pandas中的NaN;这不会显示在上面的df.head()输出中。这是在errors='coerce'函数中使用pd.to_numeric的结果。