2017-06-16 7 views
4

ich eine große Menge von Daten, die ich zwei Spalten zu extrahieren, die ich weiter unten so mit dem Code zu tun verwaltet:Pandas Datenrahmen - wie zu gruppieren und Tag Reihen

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() 

jede Datei aus pk Liste Ordner enthält 10 Spalten, und der obige Code zieht zwei Spalten aus der Datei in den Plistcollect-Datenrahmen. Der Nachteil für mich ist, dass die File-Pull-Iteration die Daten an den unteren Rand der vorherigen Daten anfügt. Ein Datum wie folgt aussieht:

Number Exp. m/z Intensity 
1   1013.33  1000 
2   1257.52  2000 

und so weiter, und mit append:

Number Exp. m/z Intensity 
1   1013.33  1000 
2   1257.52  2000 
3   1013.35  3000 
4   1257.61  4000 

wobei 1 ~ 2 aus der ersten Datei sind, und 3 bis 4 aus der zweiten Datei, usw. . Jede Datei hat eine unterschiedliche Anzahl von Zeilen oder Indizes (d. H. Datei 1 hat 400 Zeilen, Datei 2 hat 501 Zeilen usw.), was einige Probleme in der Zeile für meinen Code verursacht. Also die Frage ist, gibt es eine Möglichkeit, jede Datei zu markieren, so dass, wenn die Dateien zum Anhängen an plistcollect iteriert werden, die Zeilen von plistcollect DataFrame mit den Namen der Dateien markiert sind, so dass ich Binning für jedes Tag durchführen kann?


Als Randbemerkung, nachdem plistcollect definieren, durchführen I Anpassung durch:

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] 

die diejenigen Exp aufnimmt. m/z-Werte, die innerhalb von ppm-Unterschieden (150 ppm) liegen, immer noch im selben Format wie Plistcollect. Dann haben Binning ich mit np.digitize von:

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) 

Das gibt mir, was ich in Bezug auf die Rohdaten Analyse wollen wie (bitte beachten Sie, dass die Zahlen für diese Tabelle nicht zum Beispiel Tabelle entsprechen oben):

Allerdings möchte ich die Intensität Werte für jede Datei normalisieren, so dass ich dachte, dass das Binning auf die separaten Daten für jede Datei erfolgen sollte. Daher frage ich, ob es eine Möglichkeit gibt, die Zeilen für plistcollect in Bezug auf jede entsprechende Datei zu kennzeichnen. Bitte beachten Sie auch, dass der Abgleich vor der Normalisierung durchgeführt werden muss. Die Normierung würde darin bestehen, jeden Intensitätswert durch die Summe der Intensitätswerte aus derselben Datendatei zu teilen. Unter Verwendung der obigen Beispieltabelle wäre die normalisierte Intensität für 1013,33: 1000/(1000 + 2000) und die für 1013,35 wäre: 3000/(3000 + 4000).

Ich kann die Summe aller Werte innerhalb jedes Bins ohne Problem berechnen, aber ich kann keinen Weg finden, um die Summe der Intensitätswerte zwischen den Bins zu finden, die dem entsprechen, wo die Werte aus dem angefügten kommen Dateien.

EDIT:

bearbeitet ich den Code, um die Antwort zu reflektieren, zusammen mit dem Hinzufügen von 'findex' zu den Spielen Datenrahmen. Nun scheint der result3-Datenrahmen die Dateinamen als Tags zu enthalten. Der Gruppen-Datenrahmen scheint auch Tag-Werte zu haben. Die Frage ist, wie definiere/gruppiere ich die Tagnamen?

filetags = groups['Tag'] 
resulttable = pd.concat([filetags, groups['Exp. m/z'].mean(), average, CV], axis=1) 

erzeugt Fehlermeldung von: kann ein Nicht-NDFrame-Objekt nicht verketten.

Edit2: Die Datei "pickuplist.xls" enthält eine Spalte namens "Masse", die einfach eine Liste von Exp enthält. m/z-Werte, die ich verwende, um das erhaltene Exp. m/z-Werte aus den angehängten Dateien (wo ppm 150 eingeht, also die exp. m/z-Werte, die innerhalb 150 ppm Differenz liegen (abs (Masse - Masse_von_Datei)/Masse * 1000000 = 150). Die Abfrageliste.xls sieht aus :

mass 
1013.34 
1079.3757 
1095.3706 
1136.3972 
1241.4285 
1257.4234 

diese sind, was ich bekannt Aufnahmeliste an, und jede Datei zu können oder auch nicht, diese Massenwerte und die Streichhölzer Definition tatsächlich auch kam von einem der Art Benutzer von Stack-Überlauf enthalten Es verwendet wird.. iterieren der plistcollect und wählt diese Exp m/z-Werte, die von 'Masse' innerhalb von 150 ppm Differenz fallen

+0

Waht ist 'print (Typ (filetags))' 'vor Result = pd.concat ([filetags, Gruppen ['Exp. m/z']. Mittelwert(), Durchschnitt, CV], Achse = 1) '? – jezrael

+0

heißt es pandas.core.groupby.SeriesGroupBy. print (filetags) nach resulttable erzeugt keinen Fehler, also muss etwas mit der Verknüpfung von filetags mit resulttable aus sein. –

+0

Ich glaube, Sie vermissen einige Aggregatfunktionen wie 'groups ['Tag']. Mean()' oder 'groups ['Tag']. Std()' – jezrael

Antwort

1

ich glaube, Sie Parameter keys in concat verwenden:..

dfs = [] 
for f in files_xls: 
    dfs = pd.read_excel(f, 'Sheet1')[['Exp. m/z','Intensity']] 
    dfs.append(data) 

Es ist die gleiche wie:

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 

EDIT:

Ich glaube, ich habe es. Need Tag Spalte zuerst zu den Spielen hinzufügen und dann von np.digitize mit Tag Spalte GROUPBY:

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 
+0

die Plistcollect-Zeile scheint einen Fehler zu erzeugen, der unerwarteten Einzug sagt bei .reset_index (level = 1, drop = True). Also habe ich das ')' aus pd.concat (dfs, keys = files_xls) entfernt und am Ende die schließende Klammer hinzugefügt (.reset_index()), was mir nun eine Fehlermeldung von list object gibt, hat kein Attribut 'reset_index' . –

+0

können Sie '\' hinzufügen oder eine lange Zeile erstellen, dann funktioniert es. – jezrael

+0

Vielen Dank für die Antwort. Es ist einfach erstaunlich, wie man mit diesem Code kommt, wenn ich mir die Haare aus dem Kopf riss und versuchte, die Lösungen herauszufinden. In jedem Fall scheint dies den Datensatz von results3 nach Tags wie beabsichtigt zu gruppieren. Wenn dann die Ergebnistabelle erstellt wird, scheinen Durchschnitt, Stdev und CV nicht berechnet zu werden. Außerdem muss ich jedes Element (Intensitätswerte) für jede Datei durch die Summe der Intensitätswerte nach dem Abgleich teilen. Also würde ich für test1.xls die Intensitätswerte summieren und dann jede Intensität durch die Summe dividieren. Gibt es einen Weg dazu? Ich entschuldige mich, wenn ich zu viel frage. –

Verwandte Themen