2017-03-11 3 views
0

Ich habe einen Datensatz, die wie folgt aussieht:Iterieren über eine Säule und einen Wert mit einer extrahierten Zeichenfolge [Pandas] ersetzt

A B 
1 aa 1234 
2 ab 3456 
3 bc [1357, 2468] 
4 cc 8901 
... 

Ich brauche über die Spalte B zu durchlaufen und alle Werte in eckigen Klammern ersetzen ([]) mit vier linken Ziffern in den Klammern, so dass die Datenmenge würde wie folgt aussehen:

A B 
1 aa 1234 
2 ab 3456 
3 bc 1357 
4 cc 8901 
... 

ich habe diesen Code:

for item in df['B']: 
if len(item) > 4: 
    item_v = str(item[1:5]) 
    df['B'][item] = item_v 
    print(df['B'][item]) 

Welche abgeschnittenen Werte druckt, aber, wenn ich den Kopf des df überprüfen, es hat immer noch die alten Werte:

> df['B'].head() 

    > A B 
    1 aa 1234 
    2 ab 3456 
    3 bc [1357, 2468] 
    4 cc 8901 
    ... 

Was mache ich falsch?

+0

Sind die Daten in Spalte B tatsächlich Text? Oder ist es eine Mischung aus ganzen Zahlen und Listen? Wenn Pandas die Daten als Listen speichert, haben Sie keine Länge> 4. Versuchen Sie, 'type (df.loc [3, 'B'])' 'auszuführen, um zu sehen, um welchen Typ es sich handelt, es kann eine Liste sein. – James

+0

Es ist eine Zeichenfolge. –

Antwort

1

Der einfachste und schnellste Weg ist Pandas str.get() Funktion zu verwenden und eine andere Spalte für die gewünschten Ergebnisse zu erstellen.

Lösung 1 Diese erste Lösung funktioniert, wenn Ihre Werte in B ganze Zahlen sind [1234,3456,[1357, 2468],8901]

df['C'] = df['B'].str.get(0).astype(float) 
df.C.fillna(df['B'], inplace=True) 
df['C'] = df.C.astype(int, inplace=True) 

Ausgang:

A    B  C 
0 aa   1234 1234 
1 ab   3456 3456 
2 bc [1357, 2468] 1357 
3 cc   8901 8901 

Dann können Sie Spalte B löschen, wenn Sie nicht tun brauchen.

Lösung # 2 Diese Lösung funktioniert, wenn Ihre Werte in B Strings sind ['1234','3456',['1357', '2468'],'8901']

import re 
df['digits'] = df['B'].apply(lambda x: re.findall('\d+', str(x))) 
df['digits'] = df['digits'].str.get(0) 
print(df) 

Ausgang:

A    B digits 
0 aa   1234 1234 
1 ab   3456 3456 
2 bc [1357, 2468] 1357 
3 cc   8901 8901 

Auch hier können Sie die Spalte B löschen, wenn Sie nicht brauchen, es.

+0

Joe, guter Ansatz, aber als ich den Code lief, bekam ich nur die erste Ziffer der 4 in Spalte C. Für die dritte Zeile bekam ich die eckige Klammer ([) in Spalte C. Außerdem brauche ich B/C um Sei eine Zeichenfolge. –

+0

@FeyziBagirov Also sieht dein Wert wahrscheinlich so aus "[1357, 2468]". Es ist keine Liste von ganzen Zahlen, es ist eine Zeichenfolge. Du hättest das erklären sollen. –

+0

@FeyziBagirov Ich werde meine Antwort bearbeiten. –

0

In Ihrem Code durchlaufen Sie die Elemente in Spalte B des Datenrahmens, aber Sie haben keine Möglichkeit, in Ihren ursprünglichen Datenrahmen zu indizieren. Insbesondere die Zeile:

df['B'][item] = item_v,

nicht tun, was Sie wollen. Es platziert einen neuen Artikel in Spalte B mit einem Index von item. Wenn Sie es mit einem kleinen Datenrahmen versuchen, werden Sie wahrscheinlich einige ungerade Werte am Ende des Rahmens sehen. Als ich dies versuchen, erhalte ich:

In[36]: df 
Out[36]: 
    A  B 
0 aa 1234 
1 ab 3456 
2 bc 1357 
3 cc 8901 

In[37]: df['B'][item] = item_v 

In[38]: df['B'] 
Out[38]: 
0  1234 
1  3456 
2  1357 
3  8901 
8901 8901 <-- ??? 
Name: B, dtype: object 

Erschwerend kommt hinzu, wird diese Zeile nicht den Wert in den Datenrahmen einfügen, wo man erwarten würde. Das neue Element wird nur angezeigt, wenn Sie df['B'] betrachten. Wenn Sie nur df betrachten, sehen Sie den ursprünglichen Datenrahmen ohne den zusätzlichen Gegenstand.

Der richtige Weg ist es, Elemente zu setzen in einem Datenrahmen .loc[] dergleichen zu verwenden ist:

df.loc[item,'B'] = item_v

tut dies noch nicht das ursprüngliche Problem lösen, das ist, wie den korrekten Index zu erhalten. Ein Update für Ihren ursprünglichen Code ist Wert zu akkumulieren für jedes Element in der Spalte B in einer Liste und dann auf der Spalte B wie folgt vergeben zurück:

newB = [] 
for item in df['B']: 
    if len(item) > 4: 
     item_v = str(item[1:5]) 
    else: 
     item_v = item 
    newB.append(item_v) 
print(newB) 
df.loc[:, 'B'] = newB 

jedoch mit pandas gibt es auch Lösungen, die nicht erfordern direkt über die Elemente in Spalte B.

Zum Beispiel können Sie verwenden, um nur die Zeichenfolgen länger als 4 Zeichen zusammen mit den .str Funktionen zu ändern, um die Textelemente zu ändern. Dieses Motto wird die Arbeit machen:

df.loc[:,'B'] = df['B'].where((df['B'].str.len() <= 4), df['B'].str[1:5]) 

Diese Anweisung erstellt eine Serie, die das Element aus der Spalte B enthält, wenn es 4 oder weniger Zeichen, oder die Scheibe [1: 5] des Elements in Spalte B, wenn es ist länger als 4 Zeichen. Diese Reihe wird dann zugewiesen, um die Spalte B in df zu ersetzen.

Verwandte Themen