我有一大组数据,我想提取两列,我设法用下面的代码做到了这一点:
import pandas as pd
import numpy as np
import os
pickupfile = 'pickuplist.xls'
path = os.chdir('some path')
files = os.listdir(path)
files_xls = [f for f in files if f[-3:] == 'xls']
df = pd.DataFrame()
pl = pd.ExcelFile(pickupfile)
pickuplist = pd.read_excel(pl)
df = [pd.read_excel(f, 'Sheet1')[['Exp. m/z','Intensity']] for f in files_xls]
plistcollect = pd.concat(df, keys=files_xls)\
.reset_index(level=1, drop=True)\
.rename_axis('Tag')\
.reset_index()
pk 列表文件夹中的每个文件包含 10 列,上面的代码将文件中的两列拉入 plistcollect 数据框。对我来说不利的是,文件拉取迭代会将数据附加到先前数据的底部。一个数据看起来像:
Number Exp. m/z Intensity
1 1013.33 1000
2 1257.52 2000
等等,并附加:
Number Exp. m/z Intensity
1 1013.33 1000
2 1257.52 2000
3 1013.35 3000
4 1257.61 4000
其中1~2来自第一个文件,3~4来自第二个文件,依此类推。每个文件都有不同数量的行或索引(即文件 1 有 400 行,文件 2 有 501 行,等等),这导致我的代码出现一些问题。所以问题是,有没有办法标记每个文件,以便在迭代文件以附加到 plistcollect 时,plistcollect DataFrame 的行标记有文件名,这样我就可以对每个文件进行分箱标签?
附带说明,在定义 plistcollect 之后,我通过以下方式执行匹配:
ppm = 150
matches = pd.DataFrame(index=pickuplist['mass'], columns=plistcollect.set_index(list(plistcollect.columns)).index, dtype=bool)
for index, findex, exp_mass, intensity in plistcollect.itertuples():
matches[findex, exp_mass] = abs(matches.index - exp_mass) / matches.index < ppm / 1e6
results = {i: list(s.index[s]) for i, s in matches.iterrows()}
results2 = {key for key, value in matches.any().iteritems() if value}
results3 = matches.any().reset_index()[matches.any().values]
它拾取那些 Exp。落在 ppm 差异 (150 ppm) 范围内的 m/z 值,仍然采用与 plistcollect 相同的格式。然后我通过 np.digitize 进行装箱:
bins = np.arange(900, 3000, 1)
groups = results3.groupby(np.digitize(results3['Exp. m/z'], bins))
stdev = groups['Intensity'].std()
average = groups['Intensity'].mean()
CV = stdev/average*100
resulttable = pd.concat([groups['Exp. m/z'].mean(),average,CV], axis=1)
resulttable.columns.values[1] = 'Average'
resulttable.columns.values[2] = 'CV'
resulttable.to_excel('test.xls', index=False)
这给出了我想要的原始数据分析,例如(请注意,此表的数字与上面的示例表不对应):
Exp. m/z Average CV
1013.32693 582361.5354 13.49241757
1257.435414 494927.0904 12.45206038
但是,我想标准化每个数据文件的强度值,所以我认为应该对每个文件的单独数据进行分箱。因此,为什么我要问是否有办法针对每个相应文件标记 plistcollect 的行。另请注意,匹配过程必须在归一化之前完成。归一化是将每个强度值除以来自同一数据文件的强度值的总和。使用上面的示例表,1013.33 的归一化强度为:1000/(1000+2000),而 1013.35 的归一化强度为:3000/(3000+4000)。
我可以毫无问题地计算每个 bin 中所有值的总和,但我似乎无法找到一种方法来找到对应于值来自附加文件的 bin 之间的强度值总和.
编辑:
我编辑了代码以反射(reflect)答案,同时将“findex”添加到匹配数据框中。现在 results3 数据框似乎包含文件名作为标签。 groups dataframe 似乎也有 Tag 值。问题是,如何通过标签名称指定/分组?
filetags = groups['Tag']
resulttable = pd.concat([filetags, groups['Exp. m/z'].mean(), average, CV], axis=1)
产生错误消息:无法连接非 NDFrame 对象。
编辑2: pickuplist.xls 文件包含一个名为“mass”的列,其中只有一个 Exp 列表。我用来提取获得的 Exp 的 m/z 值。来自附加文件的 m/z 值(其中 ppm 150 进来,所以那些 Exp.m/z 值落在 150 ppm 差异内(abs(质量 - mass_from_file)/质量* 1000000 = 150)。pickuplist.xls 看起来像:
mass
1013.34
1079.3757
1095.3706
1136.3972
1241.4285
1257.4234
这些就是我所说的已知拾取列表,每个文件可能包含也可能不包含这些质量值。而匹配定义实际上也来自 Stack Overflow 的一位好心用户。它用于遍历 plistcollect,并选择那些 Exp。与“质量”相差 150 ppm 以内的 m/z 值。
最佳答案
我想你可以在 concat
中使用参数 keys
:
dfs = []
for f in files_xls:
dfs = pd.read_excel(f, 'Sheet1')[['Exp. m/z','Intensity']]
dfs.append(data)
它等同于:
dfs = [pd.read_excel(f, 'Sheet1')[['Exp. m/z','Intensity']] for f in files_xls]
plistcollect = pd.concat(dfs, keys=files_xls) \
.reset_index(level=1, drop=True) \
.rename_axis('Tag') \
.reset_index()
print (plistcollect)
Tag Exp.m/z Intensity
0 test1.xls 1013.33 1000
1 test1.xls 1257.52 2000
2 test2.xls 1013.35 3000
3 test2.xls 1257.61 4000
编辑:
我想我明白了。需要先将 Tag
列添加到匹配项,然后通过 np.digitize
和 Tag
列进行分组:
print (plist)
Tag Exp. m/z Intensity
0 test1.xls 1000 2000
1 test1.xls 1000 1500
2 test1.xls 2000 3000
3 test2.xls 3000 4000
4 test2.xls 4000 5000
5 test2.xls 4000 5500
pickup = pd.DataFrame({'mass':[1000,1200,1300, 4000]})
print (pickup)
mass
0 1000
1 1200
2 1300
3 4000
matches = pd.DataFrame(index=pickup['mass'],
columns = plist.set_index(list(plist.columns)).index,
dtype=bool)
ppm = 150
for index, tags, exp_mass, intensity in plist.itertuples():
matches[(tags, exp_mass)] = abs(matches.index - exp_mass) / matches.index < ppm / 1e6
print (matches)
Tag test1.xls test2.xls
Exp. m/z 1000 2000 3000 4000
Intensity 2000 1500 3000 4000 5000 5500
mass
1000 True True False False False False
1200 False False False False False False
1300 False False False False False False
4000 False False False False True True
results3 = matches.any().reset_index(name='a')[matches.any().values]
print (results3)
Tag Exp. m/z Intensity a
0 test1.xls 1000 2000 True
1 test1.xls 1000 1500 True
4 test2.xls 4000 5000 True
5 test2.xls 4000 5500 True
bins = np.arange(900, 3000, 1)
groups = results3.groupby([np.digitize(results3['Exp. m/z'], bins), 'Tag'])
resulttable = groups.agg({'Intensity':['mean','std'], 'Exp. m/z': 'mean'})
resulttable.columns = resulttable.columns.map('_'.join)
resulttable['CV'] = resulttable['Intensity_std'] / resulttable['Intensity_mean'] * 100
d = {'Intensity_mean':'Average','Exp. m/z_mean':'Exp. m/z'}
resulttable = resulttable.reset_index().rename(columns=d) \
.drop(['Intensity_std', 'level_0'],axis=1)
print (resulttable)
Tag Average Exp. m/z CV
0 test1.xls 1750 1000 20.203051
1 test2.xls 5250 4000 6.734350
关于python - pandas DataFrame - 如何对行进行分组和标记,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44584311/