Mam pandas dataframe
w którym jedna kolumna ciągów tekstowych zawiera wartości oddzielone przecinkami. Chcę podzielić każde pole CSV i utworzyć nowy wiersz dla każdego wpisu (załóżmy, że CSV są czyste i trzeba je tylko podzielić na „,”). Na przykład a
powinien stać się b
:
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
Do tej pory próbowałem różnych prostych funkcji, ale .apply
metoda wydaje się przyjmować tylko jeden wiersz jako wartość zwracaną, gdy jest używana na osi, i nie mogę zabrać się .transform
do pracy. Wszelkie sugestie będą mile widziane!
Przykładowe dane:
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}])
Wiem, że to nie zadziała, ponieważ tracimy metadane DataFrame przechodząc przez numpy, ale powinno dać ci poczucie tego, co próbowałem zrobić:
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)
Odpowiedzi:
Co powiesz na coś takiego:
Następnie wystarczy zmienić nazwy kolumn
źródło
UPDATE2: bardziej ogólna funkcja wektoryzowana, która będzie działać dla wielu
normal
i wielulist
kolumnPróbny:
Wiele
list
kolumn - wszystkielist
kolumny muszą mieć tę samą liczbę elementów w każdym wierszu:zachowując oryginalne wartości indeksu:
Ustawiać:
Kolumna CSV:
za pomocą tej małej sztuczki możemy przekonwertować kolumnę podobną do CSV na
list
kolumnę:AKTUALIZACJA: ogólne podejście wektoryzowane (będzie działać również dla wielu kolumn):
Oryginalny DF:
Rozwiązanie:
najpierw przekonwertujmy ciągi CSV na listy:
Teraz możemy to zrobić:
Stara odpowiedź:
Zainspirowany rozwiązaniem @AFinkelstein , chciałem uczynić go nieco bardziej uogólnionym, który można zastosować do DF z więcej niż dwiema kolumnami i tak szybko, prawie prawie tak szybko, jak rozwiązanie AFinkelsteina):
źródło
.explode()
metodę w API (zobacz również tę odpowiedź ).Po bolesnych eksperymentach, by znaleźć coś szybszego niż zaakceptowana odpowiedź, zacząłem działać. Działał około 100 razy szybciej w zestawie danych, na którym go wypróbowałem.
Jeśli ktoś zna sposób, aby uczynić to bardziej eleganckim, to proszę zmodyfikuj mój kod. Nie mogłem znaleźć sposobu, który działałby bez ustawienia innych kolumn, które chcesz zachować jako indeks, a następnie zresetowania indeksu i zmiany nazw kolumn, ale wyobrażam sobie, że działa coś jeszcze.
źródło
TypeError: object of type 'float' has no len()
od pierwszego kroku (DataFrame(df.var1.str.split(',').tolist())
)NaN
w tej kolumnie, więc zastąpienie tob = DataFrame(a.var1.str.split(',').values.tolist(), index=a.var2).stack()
Oto funkcja, którą napisałem dla tego wspólnego zadania. Jest bardziej wydajny niż metody
Series
/stack
. Kolejność kolumn i nazwy są zachowane.Dzięki tej funkcji oryginalne pytanie jest tak proste, jak:
źródło
Pandy> = 0,25
Metody Series i DataFrame definiują
.explode()
metodę, która rozbija listy na osobne wiersze. Zobacz sekcję Dokumenty na temat Rozbijanie kolumny podobnej do listy .Ponieważ masz listę ciągów oddzielonych przecinkami, podziel ciąg na przecinku, aby uzyskać listę elementów, a następnie wywołaj
explode
tę kolumnę.Pamiętaj, że
explode
działa tylko na jedną kolumnę (na razie).NaN i puste listy otrzymują leczenie, na które zasługują, bez konieczności przeskakiwania przez obręcze, aby zrobić to dobrze.
Jest to poważna zaleta w porównaniu z rozwiązaniami opartymi na
ravel
+repeat
(które całkowicie ignorują puste listy i dławią się na NaN).źródło
Podobne pytanie jak: pandy: Jak podzielić tekst w kolumnie na wiele wierszy?
Mógłbyś:
źródło
s.name = 'var1'
TL; DR
Demonstracja
Utwórzmy nową ramkę danych z
d
listamiUwagi ogólne
Użyję
np.arange
zrepeat
produkować dataframe indeksach, które można używać ziloc
.FAQ
Dlaczego nie używam
loc
?Ponieważ indeks może nie być unikalny i użycie
loc
spowoduje zwrócenie każdego wiersza pasującego do indeksu, którego dotyczy zapytanie.Dlaczego nie użyjesz tego
values
atrybutu i nie pokroisz go?Podczas wywoływania
values
, jeśli całość ramki danych znajduje się w jednym spójnym „bloku”, Pandas zwróci widok tablicy, która jest „blokiem”. W przeciwnym razie Pandy będą musiały ułożyć razem nowy układ. Podczas brukowania tablica musi mieć jednolity typ. Często oznacza to zwrócenie tablicy o typie dtypeobject
. Używająciloc
zamiast kroićvalues
atrybut, zmniejszam się z konieczności radzenia sobie z tym.Dlaczego używacie
assign
?Kiedy używam
assign
tej samej nazwy kolumny, którą eksploduję, zastępuję istniejącą kolumnę i utrzymuję jej pozycję w ramce danych.Dlaczego wartości indeksu są powtarzane?
Dzięki zastosowaniu
iloc
na powtarzanych pozycjach wynikowy indeks pokazuje ten sam powtarzany wzór. Jedno powtórzenie dla każdego elementu listy lub łańcucha.Można to zresetować za pomocą
reset_index(drop=True)
Do strun
Nie chcę przedwcześnie rozdzielać łańcuchów. Zamiast tego liczę wystąpienia
sep
argumentu, zakładając, że gdybym miał podzielić, długość wynikowej listy byłaby o jeden większa niż liczba separatorów.Następnie używam tego
sep
dojoin
łańcuchówsplit
.Dla list
Podobnie jak w przypadku ciągów, z tym wyjątkiem, że nie muszę liczyć wystąpień,
sep
ponieważ jest już podzielony.Używam Numpy
concatenate
do łączenia list razem.źródło
Istnieje możliwość podzielenia i rozbicia ramki danych bez zmiany jej struktury
Wejście:
Na zewnątrz:
Edycja-1
Ponownie zaindeksuj na podstawie kolumny odniesienia i wyrównaj informacje o wartości kolumny ze stosem
Na zewnątrz:
źródło
Wymyśliłem rozwiązanie dla ramek danych z dowolną liczbą kolumn (wciąż oddzielając tylko wpisy jednej kolumny na raz).
źródło
Oto dość prosty komunikat, który używa
split
metody zstr
akcesorium pand, a następnie używa NumPy do spłaszczenia każdego wiersza w jedną tablicę.Odpowiednie wartości są pobierane przez powtórzenie niepodzielonej kolumny z odpowiednią liczbą razy
np.repeat
.źródło
Walczę z brakiem pamięci, używając różnych sposobów na rozbicie moich list, więc przygotowałem testy porównawcze, które pomogą mi zdecydować, które odpowiedzi odpowiedzieć. Testowałem pięć scenariuszy o różnych proporcjach długości listy do liczby list. Udostępnianie wyników poniżej:
Czas: (mniej znaczy lepiej, kliknij, aby wyświetlić dużą wersję)
Szczytowe użycie pamięci: (mniej znaczy lepiej)
Wnioski :
Pełne informacje (funkcje i kod porównawczy) znajdują się w tej liście GitHub . Należy pamiętać, że problem testu porównawczego został uproszczony i nie obejmował podziału ciągów znaków na listę - które większość rozwiązań działała w podobny sposób.
źródło
W oparciu o doskonałe rozwiązanie @ DMulligan , tutaj jest ogólna funkcja wektoryzacji (bez pętli), która dzieli kolumnę ramki danych na wiele wierszy i łączy ją z powrotem w oryginalną ramkę danych. Wykorzystuje również wielką ogólną
change_column_order
funkcję z tej odpowiedzi .Przykład:
Pamiętaj, że zachowuje oryginalny indeks i kolejność kolumn. Działa również z ramkami danych, które mają indeks niesekwencyjny.
źródło
Podział funkcji łańcuchowej może przyjmować opcjonalny argument logiczny „rozwinąć”.
Oto rozwiązanie wykorzystujące ten argument:
źródło
Po prostu użyłem doskonałej odpowiedzi Jilna z góry, ale musiał rozwinąć się, aby podzielić wiele kolumn. Myślałem, że podzielę się.
źródło
zaktualizowałem odpowiedź MaxU z obsługą MultiIndex
źródło
One-liner użyciu
split(___, expand=True)
alevel
iname
argumentyreset_index()
:Jeśli chcesz
b
wyglądać dokładnie tak jak w pytaniu, możesz dodatkowo:źródło
Wymyśliłem następujące rozwiązanie tego problemu:
źródło
Inne rozwiązanie korzystające z pakietu kopii Pythona
źródło
Tutaj jest wiele odpowiedzi, ale jestem zaskoczony, że nikt nie wspomniał o wbudowanej funkcji wybuchania pand. Sprawdź poniższy link: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.explode.html#pandas.DataFrame.explode
Z jakiegoś powodu nie mogłem uzyskać dostępu do tej funkcji, więc użyłem poniższego kodu:
Powyżej znajduje się próbka moich danych. Jak widać kolumna osób zawierała szereg ludzi, a ja próbowałem ją rozbić. Podany przeze mnie kod działa dla danych typu listy. Spróbuj więc przenieść dane tekstowe rozdzielone przecinkami do formatu listy. Ponieważ mój kod korzysta z wbudowanych funkcji, jest znacznie szybszy niż funkcje niestandardowe / zastosuj.
Uwaga: Może być konieczne zainstalowanie pandas_explode za pomocą pip.
źródło
Miałem podobny problem, moim rozwiązaniem było najpierw przekonwertowanie ramki danych na listę słowników, a następnie przejście. Oto funkcja:
Przykład:
Możesz także nieco zmienić funkcję, aby obsługiwała oddzielanie wierszy typu listy.
źródło