Próbuję dokładnie podkreślić, co zmieniło się między dwiema ramkami danych.
Załóżmy, że mam dwie ramki danych Python Pandas:
"StudentRoster Jan-1":
id Name score isEnrolled Comment
111 Jack 2.17 True He was late to class
112 Nick 1.11 False Graduated
113 Zoe 4.12 True
"StudentRoster Jan-2":
id Name score isEnrolled Comment
111 Jack 2.17 True He was late to class
112 Nick 1.21 False Graduated
113 Zoe 4.12 False On vacation
Moim celem jest utworzenie tabeli HTML, która:
- Identyfikuje wiersze, które uległy zmianie (mogą to być int, float, boolean, string)
Wyprowadza wiersze z takimi samymi, OLD i NEW wartościami (najlepiej w tabeli HTML), aby konsument mógł wyraźnie zobaczyć, co zmieniło się między dwiema ramkami danych:
"StudentRoster Difference Jan-1 - Jan-2": id Name score isEnrolled Comment 112 Nick was 1.11| now 1.21 False Graduated 113 Zoe 4.12 was True | now False was "" | now "On vacation"
Przypuszczam, że mógłbym zrobić porównanie wiersz po wierszu i kolumna po kolumnie, ale czy istnieje prostszy sposób?
df.compare
.Odpowiedzi:
Pierwsza część jest podobna do Constantine, możesz uzyskać wartość logiczną określającą, które wiersze są puste *:
Następnie możemy zobaczyć, które wpisy się zmieniły:
Tutaj pierwszy wpis to indeks, a drugi kolumny, które zostały zmienione.
* Uwaga: ważne jest,
df1
idf2
dzielić ten sam indeks tutaj. Aby przezwyciężyć tę niejednoznaczność, możesz upewnić się, że patrzysz tylko na wspólne etykiety przy użyciudf1.index & df2.index
, ale myślę, że zostawię to jako ćwiczenie.źródło
df1
z tym, co jest na pierwszym miejscudf2
, niezależnie od wartości indeksu. JFYI na wypadek, gdybym nie był jedyną osobą, dla której to nie było oczywiste. ; D Dzięki!nan
w obu df1 i df1, ta funkcja zgłosi zmianę znan
nanan
. To dlatego, żenp.nan != np.nan
wracaTrue
.Podkreślenie różnicy między dwoma DataFrames
Możliwe jest użycie właściwości stylu DataFrame do podświetlenia koloru tła komórek, w których występuje różnica.
Na podstawie przykładowych danych z oryginalnego pytania
Pierwszym krokiem jest poziome konkatenowanie ramek DataFrames z
concat
funkcją i rozróżnianie każdej klatki za pomocąkeys
parametru:Prawdopodobnie łatwiej jest zamienić poziomy kolumn i umieścić obok siebie te same nazwy kolumn:
Teraz znacznie łatwiej jest dostrzec różnice w ramkach. Ale możemy pójść dalej i użyć tej
style
właściwości do wyróżnienia komórek, które są różne. W tym celu definiujemy funkcję niestandardową, którą można zobaczyć w tej części dokumentacji .Podświetli to komórki, w których obie mają brakujące wartości. Możesz je wypełnić lub podać dodatkową logikę, aby nie były podświetlane.
źródło
df_final[(df != df2).any(1)].style.apply(highlight_diff, axis=None)
Ta odpowiedź po prostu rozszerza @Andy Hayden, czyniąc ją odporną na działanie pól numerycznych
nan
i opakowując ją w funkcję.Tak więc z twoimi danymi (lekko edytowanymi, aby mieć NaN w kolumnie wyników):
Wynik:
źródło
wydruki
źródło
id
jako indeksu, todf.groupby(level='id')
wywołuje błąd i nie jestem pewien dlaczego ...Napotkałem ten problem, ale znalazłem odpowiedź przed znalezieniem tego postu:
W oparciu o odpowiedź unutbu załaduj swoje dane ...
... zdefiniuj swoją funkcję diff ...
Następnie możesz po prostu użyć panelu, aby podsumować:
Nawiasem mówiąc, jeśli jesteś w ipython notebooki, może chcesz użyć kolorowego diff funkcję dać kolory w zależności od tego, czy komórki są różne, są równe lub lewo / prawo NULL:
źródło
my_panel = pd.Panel(dict(df1=df1,df2=df2))
funkcjireport_diff()
? Mam na myśli, czy można to zrobić:print report_diff(df1,df2)
i uzyskać takie same wyniki, jak twoja instrukcja drukowania?pd.Panel(dict(df1=df1,df2=df2)).apply(report_diff, axis=0)
- to jest niesamowite!!!Jeśli twoje dwie ramki danych mają w sobie te same identyfikatory, ustalenie, co się zmieniło, jest w rzeczywistości dość łatwe. Samo zrobienie
frame1 != frame2
tego da ci boolowską ramkę DataFrame, w której każdaTrue
zawiera dane, które uległy zmianie. Dzięki temu możesz łatwo uzyskać indeks każdego zmienionego wiersza, wykonującchangedids = frame1.index[np.any(frame1 != frame2,axis=1)]
.źródło
Inne podejście z użyciem concat i drop_duplicates:
Wynik:
źródło
Po pogrzebaniu z odpowiedzią @ journois, byłem w stanie zmusić go do pracy przy użyciu MultiIndex zamiast Panelu z powodu braku panelu .
Najpierw utwórz fikcyjne dane:
Następnie zdefiniuj swoją funkcję diff , w tym przypadku użyję tej z jego odpowiedzi
report_diff
pozostaje taka sama:Następnie zamierzam połączyć dane w ramkę danych MultiIndex:
I na koniec zastosuję
report_diff
dół każdej grupy kolumn:To daje:
I to wszystko!
źródło
Rozszerzam odpowiedź @cge, co jest całkiem fajne dla większej czytelności wyniku:
Pełny przykład demonstracyjny:
źródło
Oto inny sposób korzystania z funkcji wybierania i scalania:
Oto to samo ze zrzutu ekranu Jupyter:
źródło
pandy> = 1,1:
DataFrame.compare
Dzięki pandom 1.1 można zasadniczo powielić dane wyjściowe Teda Petrou za pomocą pojedynczego wywołania funkcji. Przykład zaczerpnięty z dokumentów:
Tutaj „self” odnosi się do LHS dataFrame, podczas gdy „inne” to RHS DataFrame. Domyślnie równe wartości są zastępowane przez NaN, więc możesz skupić się tylko na różnicach. Jeśli chcesz wyświetlić równe wartości, użyj
Możesz także zmienić oś porównania za pomocą
align_axis
:To porównuje wartości wierszami, a nie kolumnami.
źródło
Funkcja znajdująca asymetryczną różnicę między dwiema ramkami danych jest zaimplementowana poniżej: (Na podstawie różnicy zestawu dla pand ) GIST: https://gist.github.com/oneryalcin/68cf25f536a25e65f0b3c84f9c118e03
Przykład:
źródło
import pandy jako pd import numpy jako np
df = pd.read_excel ('D: \ HARISH \ DATA SCIENCE \ 1 MY Training \ SAMPLE DATA & projs \ CRICKET DATA \ LISTA ODTWARZACZY IPL \ LISTA ODTWARZACZY IPL _ harish.xlsx')
df1 = srh = df [df ['ZESPÓŁ']. str.contains ("SRH")] df2 = csk = df [df ['ZESPÓŁ']. str.contains ("CSK")]
srh = srh.iloc [:, 0: 2] csk = csk.iloc [:, 0: 2]
csk = csk.reset_index (drop = True) csk
srh = srh.reset_index (drop = True) srh
nowy = pd.concat ([srh, csk], axis = 1)
new.head ()
** TYP ODTWARZACZA TYP ODTWARZACZA
0 David Warner Batsman ... MS Dhoni Kapitan
1 Bhuvaneshwar Kumar Bowler ... Ravindra Jadeja All-Rounder
2 Manish Pandey Batsman ... Suresh Raina All-Rounder
3 Rashid Khan Arman Bowler ... Kedar Jadhav All-Rounder
4 Shikhar Dhawan Batsman… Dwayne Bravo All-Rounder
źródło