2015-11-13 16 views
5

Ich habe eine CSV mit Zeilen wie folgt aussehen Datei:Daten munging in Pandas

ID,98.4,100M,55M,65M,75M,100M,75M,65M,100M,98M,100M,100M,92M,0#,0N#, 

kann ich es lesen mit

#!/usr/bin/env python 

import pandas as pd 
import sys 

filename = sys.argv[1] 
df = pd.read_csv(filename) 

eine bestimmte Spalte gegeben, ich möchte die Zeilen aufzuspalten durch ID und geben Sie dann den Mittelwert und die Standardabweichung für jede ID aus.

Mein erstes Problem ist, wie kann ich alle nichtnumerischen Teile von den Nummern wie "100M" und "0N #" entfernen, die jeweils 100 und 0 sein sollten.

Ich habe auch versucht, über den entsprechenden Header Looping und in Pandas DataFrame: remove unwanted parts from strings in a column

df[header].replace(regex=True,inplace=True,to_replace=r'\D',value=r'') 

wie vorgeschlagen verwenden.

Jedoch ändert dies 98,4 in 984.

+0

Mögliche Duplikat [Pandas Datenrahmen: Entfernen Sie unerwünschte Teile von Zeichenketten in einer Spalte] (http: // stackoverflow.com/questions/13682044/pandas-dataframe-remove-unwanted-parts-from-strings-in-a-column) – Evert

+0

@Evert Eine Bearbeitung hinzugefügt, um zu zeigen, wie ich auch mit Dezimalstellen umgehen muss. – eleanora

+0

Das Duplikat, das ich aufgelistet habe, schlägt vor, 'rstrip' zu verwenden, mit den Zeichen, die Sie entfernen möchten. Also ... 'rstrip ('MN #')' sollte gut für Ihre Eingabe arbeiten, mit dem Lambda vorgeschlagen in dem Duplikat (natürlich können Sie den 'lstrip' Teil weglassen). – Evert

Antwort

3

Verwendung str.extract:

In [356]: 
import io 
import pandas as pd 
t="""ID,98.4,100M,55M,65M,75M,100M,75M,65M,100M,98M,100M,100M,92M,0#,0N#""" 
df = pd.read_csv(io.StringIO(t), header=None) 
df 

Out[356]: 
    0  1  2 3 4 5  6 7 8  9 10 11 12 13 \ 
0 ID 98.4 100M 55M 65M 75M 100M 75M 65M 100M 98M 100M 100M 92M 

    14 15 
0 0# 0N# 

In [357]: 
for col in df.columns[2:]: 
    df[col] = df[col].str.extract(r'(\d+)').astype(int) 
df 

Out[357]: 
    0  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 
0 ID 98.4 100 55 65 75 100 75 65 100 98 100 100 92 0 0 

Wenn Sie Float-Zahlen, dann können Sie die folgende regex verwenden:

In [379]: 
t="""ID,98.4,100.50M,55.234M,65M,75M,100M,75M,65M,100M,98M,100M,100M,92M,0#,0N#""" 
df = pd.read_csv(io.StringIO(t), header=None) 
df 

Out[379]: 
    0  1  2  3 4 5  6 7 8  9 10 11 \ 
0 ID 98.4 100.50M 55.234M 65M 75M 100M 75M 65M 100M 98M 100M 

    12 13 14 15 
0 100M 92M 0# 0N# 

In [380]:  
for col in df.columns[2:]: 
    df[col] = df[col].str.extract(r'(\d+\.?\d+)').astype(np.float) 
df 

Out[380]: 
    0  1  2  3 4 5 6 7 8 9 10 11 12 13 14 15 
0 ID 98.4 100.5 55.234 65 75 100 75 65 100 98 100 100 92 NaN NaN 

so (\d+\.?\d+) für Gruppen sieht enthält \d+ 1 oder mehr Ziffern mit \.? optionalen Dezimalpunkt und \d+ 1 oder mehr weiteren Stellen nach dem Komma

EDIT

OK bearbeiten meine RegexMuster:

In [408]: 
t="""Name,97.7,0A,0A,65M,0A,100M,5M,75M,100M,90M,90M,99M,90M,0#,0N#""" 
df = pd.read_csv(io.StringIO(t), header=None) 
df 

Out[408]: 
    0  1 2 3 4 5  6 7 8  9 10 11 12 13 14 \ 
0 Name 97.7 0A 0A 65M 0A 100M 5M 75M 100M 90M 90M 99M 90M 0# 

    15 
0 0N# 

In [409]:  
for col in df.columns[2:]: 
    df[col] = df[col].str.extract(r'(\d+\.*\d*)').astype(np.float) 
df 

Out[409]: 
    0  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 
0 Name 97.7 0 0 65 0 100 5 75 100 90 90 99 90 0 0 
+0

df = pd.read_csv (io.StringIO (t), Header = Keine) TypeError: initial_value muss Unicode oder None sein, nicht str – eleanora

+0

Ignoriere das 'io.StringIO' Bit, das ich gerade in deinem Text als gelesen habe Dateiobjekt in Ihrem Fall 'df = pd.read_csv (Dateiname)' ist in Ordnung – EdChum

+0

Wenn dies die ganze Datei "Name" ist, 97.7,0A, 0A, 65M, 0A, 100M, 5M, 75M, 100M, 90M, 90M, 99M, 90M, 0 #, 0N #, "Ihr Code gibt mir" 0 Name NaN NaN NaN 65 NaN 100 NaN 75 100 90 90 99 90 NaN NaN NaN " – eleanora

2

My first problem is, how can I remove all the non-numeric parts from the numbers such as "100M" and "0N#" which should be 100 and 0 respectively.

import re 
df = pd.read_csv(yourfile, header=None) 
df.columns = ['ID'] + list(df.columns)[1:] 
df = df.stack().apply(lambda v: re.sub('[^0-9]','', v) 
       if isinstance(v, str) else v).astype(float).unstack() 
df.groupby('ID').agg(['std', 'mean']) 

Hier .stack() wandeln den Datenrahmen in eine Serie, .apply() ruft das Lambda für jeden Wert auf, re.sub() entfernt alle nicht numerischen Zeichen, .astype() konvertiert in numerisch und unstack() wandelt die Serie in einen Datenrahmen um. Dies funktioniert sowohl für Ganzzahlen als auch für Fließkommazahlen gleichermaßen.

Given a particular column, I would like to split the rows by ID and then output the mean and standard deviation for each ID.

# for all columns 
df.groupby('ID').agg(['std', 'mean']) 
# for specific column 
df.groupby('ID')['<colname>'].agg(['std', 'mean']) 

output dataframe

Hier ist die im Beispiel verwendeten Daten:

from StringIO import StringIO 
s=""" 
1,98.4,100M,55M,65M,75M,100M,75M,65M,100M,98M,100M,100M,92M,0#,0N#, 
1,98.4,100M,55M,65M,75M,100M,75M,65M,100M,98M,100M,100M,92M,0#,0N#, 
2,98.4,100M,55M,65M,75M,100M,75M,65M,100M,98M,100M,100M,92M,0#,0N#, 
2,98.4,100M,55M,65M,75M,100M,75M,65M,100M,98M,100M,100M,92M,0#,0N#, 
""" 
yourfile = StringIO(s)