359 Stimmen

Teilen (aufteilen) Sie den Zeichenfolgeneintrag des Pandas-Datenrahmens in separate Zeilen auf

Ich habe ein Pandas DataFrame, in dem eine Spalte mit Textzeichenfolgen Komma-getrennte Werte enthält. Ich möchte jedes CSV-Feld aufteilen und für jeden Eintrag eine neue Zeile erstellen (angenommen, dass das CSV sauber ist und nur auf ',' aufgeteilt werden muss). Zum Beispiel sollte a zu b werden:

In [7]: a
Out[7]: 
    var1  var2
0  a,b,c     1
1  d,e,f     2

In [8]: b
Out[8]: 
  var1  var2
0    a     1
1    b     1
2    c     1
3    d     2
4    e     2
5    f     2

Bisher habe ich verschiedene einfache Funktionen ausprobiert, aber die Methode .apply scheint nur einen Zeilenwert als Rückgabewert zu akzeptieren, wenn sie auf einer Achse verwendet wird, und ich kann .transform nicht zum Laufen bringen. Über jede Hilfe würde ich mich freuen!

Beispieldaten:

from pandas import DataFrame
import numpy as np
a = DataFrame([{'var1': 'a,b,c', 'var2': 1},
               {'var1': 'd,e,f', 'var2': 2}])
b = DataFrame([{'var1': 'a', 'var2': 1},
               {'var1': 'b', 'var2': 1},
               {'var1': 'c', 'var2': 1},
               {'var1': 'd', 'var2': 2},
               {'var1': 'e', 'var2': 2},
               {'var1': 'f', 'var2': 2}])

Ich weiß, dass dies nicht funktioniert, weil wir durch die Verwendung von NumPy die Meta-Daten des DataFrame verlieren, aber es sollte Ihnen eine Vorstellung davon geben, was ich zu tun versucht habe:

def fun(row):
    letters = row['var1']
    letters = letters.split(',')
    out = np.array([row] * len(letters))
    out['var1'] = letters
a['idx'] = range(a.shape[0])
z = a.groupby('idx')
z.transform(fun)

3 Stimmen

Andere Lösungen auf dieser Seite funktionieren, aber ich fand die folgende kurz und effektiv. stackoverflow.com/questions/27263805/…

2 Stimmen

Für andere, die diese Seite besuchen und nach einer Lösung suchen, die mehrere Spalten beibehält, werfen Sie einen Blick auf diese Frage: stackoverflow.com/questions/17116814/…

2voto

Bernard Agbemadon Punkte 101

Ich schätze die Antwort von "Chang She" wirklich, aber die iterrows() Funktion dauert lange auf großen Datensätzen. Ich hatte mit diesem Problem zu kämpfen und bin zu folgendem Lösungsansatz gekommen.

# Zuerst den Index zurücksetzen, um ihn in eine Spalte zu verwandeln
a = a.reset_index().rename(columns={'index':'duplicated_idx'})

# Eine längere Serie mit explodierten Zellen zu Zeilen erhalten
series = pd.DataFrame(a['var1'].str.split('/')
                      .tolist(), index=a.duplicated_idx).stack()

# Neues DataFrame aus der Serie erstellen und mit dem alten zusammenführen
b = series.reset_index([0, 'duplicated_idx'])
b = b.rename(columns={0:'var1'})

# Optional & Fortgeschritten: Falls es außer var1 & var2 noch andere Spalten gibt
b.merge(
    a[a.columns.difference(['var1'])],
    on='duplicated_idx')

# Optional: Die Spalte "duplicated_index" löschen und die Reihenfolge der Spalten anpassen
b = b[a.columns.difference(['duplicated_idx'])]

1voto

ali bakhtiari Punkte 1031

Ein kurzer und einfacher Weg, das Format der Spalte mithilfe von .apply() zu ändern, damit es von .explode() verwendet werden kann:

import string
import pandas as pd
from io import StringIO

file = StringIO("""    var1  var2
0  a,b,c     1
1  d,e,f     2""")

df = pd.read_csv(file, sep=r'\s\s+')

df['var1'] = df['var1'].apply(lambda x : str(x).split(','))

df.explode('var1')

Ausgabe:

  var1  var2
0   a   1
0   b   1
0   c   1
1   d   2
1   e   2
1   f   2

1voto

Nur jilns ausgezeichnete Antwort von oben verwendet, aber musste erweitert werden, um mehrere Spalten aufzuteilen. Dachte, ich würde teilen.

def splitDataFrameList(df,target_column,separator):
''' df = dataframe zum teilen,
target_column = die Spalte, die die zu teilenden Werte enthält
separator = das Symbol, das zum Teilen verwendet wird

returns: ein DataFrame, bei dem jeder Eintrag für die Zielspalte getrennt ist, wobei jedes Element in eine neue Zeile verschoben wird. 
Die Werte in den anderen Spalten werden über die neu geteilten Zeilen dupliziert.
'''
def splitListToRows(row, row_accumulator, target_columns, separator):
    split_rows = []
    for target_column in target_columns:
        split_rows.append(row[target_column].split(separator))
    # Für mehrere Spalten trennen
    for i in range(len(split_rows[0])):
        new_row = row.to_dict()
        for j in range(len(split_rows)):
            new_row[target_columns[j]] = split_rows[j][i]
        row_accumulator.append(new_row)
new_rows = []
df.apply(splitListToRows,axis=1,args = (new_rows,target_column,separator))
new_df = pd.DataFrame(new_rows)
return new_df

1voto

darkhipo Punkte 1254

Meine Version der Lösung, die zu dieser Sammlung hinzugefügt werden soll! :-)

# Original problem
from pandas import DataFrame
import numpy as np
a = DataFrame([{'var1': 'a,b,c', 'var2': 1},
               {'var1': 'd,e,f', 'var2': 2}])
b = DataFrame([{'var1': 'a', 'var2': 1},
               {'var1': 'b', 'var2': 1},
               {'var1': 'c', 'var2': 1},
               {'var1': 'd', 'var2': 2},
               {'var1': 'e', 'var2': 2},
               {'var1': 'f', 'var2': 2}])
### Meine Lösung
import pandas as pd
import functools
def expand_on_cols(df, fuse_cols, delim=","):
    def expand_on_col(df, fuse_col):
        col_order = df.columns
        df_expanded = pd.DataFrame(
            df.set_index([x for x in df.columns if x != fuse_col])[fuse_col]
            .apply(lambda x: x.split(delim))
            .explode()
        ).reset_index()
        return df_expanded[col_order]
    all_expanded = functools.reduce(expand_on_col, fuse_cols, df)
    return all_expanded

assert(b.equals(expand_on_cols(a, ["var1"], delim=",")))

1voto

Shahar Katz Punkte 66

Aufgerüstete Antwort von MaxU mit Unterstützung von MultiIndex

def explode(df, lst_cols, fill_value='', preserve_index=False):
    """
    Verwendung:
        In [134]: df
        Out[134]:
           aaa  myid        num          text
        0   10     1  [1, 2, 3]  [aa, bb, cc]
        1   11     2         []            []
        2   12     3     [1, 2]      [cc, dd]
        3   13     4         []            []

        In [135]: explode(df, ['num','text'], fill_value='')
        Out[135]:
           aaa  myid num text
        0   10     1   1   aa
        1   10     1   2   bb
        2   10     1   3   cc
        3   11     2
        4   12     3   1   cc
        5   12     3   2   dd
        6   13     4
    """
    # Stellen Sie sicher, dass `lst_cols` listenähnlich ist
    if (lst_cols is not None
        and len(lst_cols) > 0
        and not isinstance(lst_cols, (list, tuple, np.ndarray, pd.Series))):
        lst_cols = [lst_cols]
    # alle Spalten außer `lst_cols`
    idx_cols = df.columns.difference(lst_cols)
    # Längen der Listen berechnen
    lens = df[lst_cols[0]].str.len()
    # ursprüngliche Indexwerte bewahren    
    idx = np.repeat(df.index.values, lens)
    res = (pd.DataFrame({
                col:np.repeat(df[col].values, lens)
                for col in idx_cols},
                index=idx)
             .assign(**{col:np.concatenate(df.loc[lens>0, col].values)
                            for col in lst_cols}))
    # Zeilen anfügen, die leere Listen haben
    if (lens == 0).any():
        # mindestens eine Zelle enthält eine leere Liste
        res = (res.append(df.loc[lens==0, idx_cols], sort=False)
                  .fillna(fill_value))
    # ursprüngliche Indexreihenfolge wiederherstellen
    res = res.sort_index()
    # Index zurücksetzen, wenn angefordert
    if not preserve_index:        
        res = res.reset_index(drop=True)

    # wenn ursprünglicher Index MultiIndex ist, erstellen Sie das DataFrame aus dem MultiIndex
    # erstellen Sie das "explodierte" DataFrame
    if isinstance(df.index, pd.MultiIndex):
        res = res.reindex(
            index=pd.MultiIndex.from_tuples(
                res.index,
                names=['number', 'color']
            )
    )
    return res

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X