Jak zrobić dobre, powtarzalne przykłady pand

Nov 21 2013

Po spędzeniu przyzwoitej ilości czasu na oglądaniu zarówno znaczników r, jak i pandy na SO, mam wrażenie, że pandaspytania z mniejszym prawdopodobieństwem zawierają odtwarzalne dane. To jest coś, że społeczność R była dobra ładna o zachęcanie, a dzięki przewodników jak to nowicjusze są w stanie uzyskać jakąś pomoc na łącząc te przykłady. Osoby, które są w stanie przeczytać te przewodniki i wrócić z odtwarzalnymi danymi, często będą miały dużo więcej szczęścia w uzyskaniu odpowiedzi na swoje pytania.

Jak możemy stworzyć dobre, powtarzalne przykłady pandaspytań? Proste ramki danych można łączyć, np .:

import pandas as pd
df = pd.DataFrame({'user': ['Bob', 'Jane', 'Alice'], 
                   'income': [40000, 50000, 42000]})

Jednak wiele przykładowych zbiorów danych wymaga bardziej skomplikowanej struktury, np .:

  • datetime indeksy lub dane
  • Wiele zmiennych kategorialnych (czy istnieje odpowiednik expand.grid()funkcji R , która daje wszystkie możliwe kombinacje pewnych podanych zmiennych?)
  • Dane MultiIndex lub panelu

W przypadku zestawów danych, które są trudne do makiety przy użyciu kilku wierszy kodu, czy istnieje odpowiednik języka R, dput()który umożliwia generowanie kodu do skopiowania i wklejania w celu ponownego wygenerowania struktury danych?

Odpowiedzi

362 AndyHayden Nov 23 2013 at 13:19

Uwaga: Pomysły tutaj są dość ogólne dla przepełnienia stosu, a nawet pytań .

Zastrzeżenie: napisanie dobrego pytania jest TRUDNE.

Dobra:

  • dołącz mały * przykład DataFrame, albo jako kod do uruchomienia:

    In [1]: df = pd.DataFrame([[1, 2], [1, 3], [4, 6]], columns=['A', 'B'])
    

    lub ustaw go jako „kopiuj i wklej” za pomocą pd.read_clipboard(sep='\s\s+'), możesz sformatować tekst do podświetlenia przepełnienia stosu i użyć Ctrl+ K(lub wstawić cztery spacje na początku każdego wiersza) lub umieścić trzy tyldy powyżej i poniżej kodu bez wcięcia kodu:

    In [2]: df
    Out[2]: 
       A  B
    0  1  2
    1  1  3
    2  4  6
    

    sprawdź pd.read_clipboard(sep='\s\s+')się.

    * Naprawdę mam na myśli małe , zdecydowana większość przykładowych ramek DataFrames może mieć mniej niż 6 wierszy potrzebnych cytowania i założę się, że mogę to zrobić w 5 wierszach. Czy możesz odtworzyć błąd za pomocą df = df.head(), jeśli nie, pogarszać się, aby sprawdzić, czy możesz stworzyć małą ramkę DataFrame, która pokazuje problem, z którym masz do czynienia.

    * Każda reguła ma wyjątek, oczywistym jest dla kwestii wydajności ( w tym przypadku na pewno użyć% timeit i ewentualnie% prun ), gdzie należy wygenerować (rozważyć użycie np.random.seed więc mamy dokładnie taką samą ramkę) df = pd.DataFrame(np.random.randn(100000000, 10)). Powiedzenie, że „zrób dla mnie ten kod szybko” nie jest ściśle związane z tematem witryny ...

  • napisz pożądany rezultat (podobnie jak powyżej)

    In [3]: iwantthis
    Out[3]: 
       A  B
    0  1  5
    1  4  6
    

    Wyjaśnij, skąd pochodzą liczby: 5 to suma kolumny B w wierszach, w których A wynosi 1.

  • pokaż kod , który wypróbowałeś:

    In [4]: df.groupby('A').sum()
    Out[4]: 
       B
    A   
    1  5
    4  6
    

    Ale powiedz, co jest nieprawidłowe: kolumna A znajduje się w indeksie, a nie w kolumnie.

  • pokaż, że zrobiłeś jakieś badania ( przeszukaj dokumenty , wyszukaj StackOverflow ), podaj podsumowanie:

    Dokumentacja sum zawiera po prostu „Oblicz sumę wartości grupy”

    Dokumentacja Groupby nie podaje na to żadnych przykładów.

    Na bok: odpowiedzią jest użycie df.groupby('A', as_index=False).sum().

  • jeśli jest to istotne, że masz kolumny Timestamp, np. próbujesz ponownie próbkować lub coś w tym rodzaju, powiedz to wyraźnie i stosuj się pd.to_datetimedo nich na wszelki wypadek **.

    df['date'] = pd.to_datetime(df['date']) # this column ought to be date..
    

    ** Czasami jest to sam problem: były to struny.

Źli:

  • nie dołączaj MultiIndex, którego nie możemy skopiować i wkleić (patrz wyżej), jest to rodzaj zażalenia z domyślnym wyświetlaniem pand, ale mimo to denerwujące:

    In [11]: df
    Out[11]:
         C
    A B   
    1 2  3
      2  6
    

    Poprawnym sposobem jest dołączenie zwykłej ramki DataFrame do set_indexwywołania:

    In [12]: df = pd.DataFrame([[1, 2, 3], [1, 2, 6]], columns=['A', 'B', 'C']).set_index(['A', 'B'])
    
    In [13]: df
    Out[13]: 
         C
    A B   
    1 2  3
      2  6
    
  • podaj wgląd w to, co to jest, dając oczekiwany wynik:

       B
    A   
    1  1
    5  0
    

    Określ dokładnie, w jaki sposób otrzymałeś liczby (jakie one są) ... dokładnie sprawdź, czy są poprawne.

  • Jeśli kod generuje błąd, dołącz cały ślad stosu (można go później edytować, jeśli jest zbyt głośny). Pokaż numer linii (i odpowiednią linię twojego kodu, przeciwko której jest podnoszony).

Brzydki:

  • nie linkuj do pliku csv, do którego nie mamy dostępu (najlepiej w ogóle nie linkuj do zewnętrznego źródła ...)

    df = pd.read_csv('my_secret_file.csv')  # ideally with lots of parsing options
    

    Większość danych jest zastrzeżona , otrzymujemy to: Zrób podobne dane i zobacz, czy możesz odtworzyć problem (coś małego).

  • nie wyjaśniaj sytuacji niejasno słowami, tak jak w przypadku ramki DataFrame, która jest „duża”, wymień niektóre nazwy kolumn na marginesie (pamiętaj, aby nie podawać ich typów). Spróbuj podać wiele szczegółów na temat czegoś, co jest całkowicie bez znaczenia, nie widząc faktycznego kontekstu. Prawdopodobnie nikt nie zamierza nawet czytać do końca tego akapitu.

    Eseje są złe, łatwiej z małymi przykładami.

  • nie uwzględniaj ponad 10 (100+ ??) wierszy danych, zanim przejdziesz do właściwego pytania.

    Proszę, widzimy tego wystarczająco dużo w naszej codziennej pracy. Chcemy pomóc, ale nie tak ... .
    Wytnij wprowadzenie i po prostu pokaż odpowiednie ramki danych (lub ich małe wersje) w kroku, który sprawia Ci kłopoty.

W każdym razie baw się dobrze, ucząc się Pythona, NumPy i Pandy!

77 JohnE May 24 2015 at 21:22

Jak tworzyć przykładowe zbiory danych

Ma to na celu głównie rozwinięcie odpowiedzi @ AndyHayden przez podanie przykładów tworzenia przykładowych ramek danych. Pandy i (szczególnie) numpy dają ci do tego różnorodne narzędzia, dzięki którym możesz ogólnie stworzyć rozsądną kopię dowolnego prawdziwego zbioru danych za pomocą zaledwie kilku linii kodu.

Po zaimportowaniu numpy i pandas, pamiętaj o podaniu losowego ziarna, jeśli chcesz, aby ludzie mogli dokładnie odtworzyć twoje dane i wyniki.

import numpy as np
import pandas as pd

np.random.seed(123)

Przykład zlewu kuchennego

Oto przykład pokazujący różne rzeczy, które możesz zrobić. Z podzbioru można utworzyć wszelkiego rodzaju przydatne przykładowe ramki danych:

df = pd.DataFrame({ 

    # some ways to create random data
    'a':np.random.randn(6),
    'b':np.random.choice( [5,7,np.nan], 6),
    'c':np.random.choice( ['panda','python','shark'], 6),

    # some ways to create systematic groups for indexing or groupby
    # this is similar to r's expand.grid(), see note 2 below
    'd':np.repeat( range(3), 2 ),
    'e':np.tile(   range(2), 3 ),

    # a date range and set of random dates
    'f':pd.date_range('1/1/2011', periods=6, freq='D'),
    'g':np.random.choice( pd.date_range('1/1/2011', periods=365, 
                          freq='D'), 6, replace=False) 
    })

To daje:

          a   b       c  d  e          f          g
0 -1.085631 NaN   panda  0  0 2011-01-01 2011-08-12
1  0.997345   7   shark  0  1 2011-01-02 2011-11-10
2  0.282978   5   panda  1  0 2011-01-03 2011-10-30
3 -1.506295   7  python  1  1 2011-01-04 2011-09-07
4 -0.578600 NaN   shark  2  0 2011-01-05 2011-02-27
5  1.651437   7  python  2  1 2011-01-06 2011-02-03

Kilka uwag:

  1. np.repeati np.tile(kolumny di e) są bardzo przydatne do tworzenia grup i indeksów w bardzo regularny sposób. W przypadku 2 kolumn można to wykorzystać do łatwego duplikowania r, expand.grid()ale jest również bardziej elastyczne pod względem możliwości zapewnienia podzbioru wszystkich permutacji. Jednak dla 3 lub więcej kolumn składnia szybko staje się nieporęczna.
  2. Aby uzyskać bardziej bezpośredni zamiennik r, expand.grid()zobacz itertoolsrozwiązanie w książce kucharskiej pandy lub np.meshgridrozwiązanie pokazane tutaj . Pozwolą one na dowolną liczbę wymiarów.
  3. Możesz zrobić całkiem sporo z np.random.choice. Na przykład w kolumnie gmamy losowy wybór 6 dat z 2011 roku. Dodatkowo ustawiając replace=Falsemożemy zapewnić, że te daty są unikalne - bardzo przydatne, jeśli chcemy użyć tego jako indeksu z unikalnymi wartościami.

Fałszywe dane giełdowe

Oprócz pobierania podzbiorów powyższego kodu, możesz dalej łączyć techniki, aby zrobić prawie wszystko. Na przykład, oto krótki przykład, który łączy np.tilei date_rangetworzy przykładowe dane giełdowe dla 4 akcji z tych samych dat:

stocks = pd.DataFrame({ 
    'ticker':np.repeat( ['aapl','goog','yhoo','msft'], 25 ),
    'date':np.tile( pd.date_range('1/1/2011', periods=25, freq='D'), 4 ),
    'price':(np.random.randn(100).cumsum() + 10) })

Teraz mamy przykładowy zestaw danych zawierający 100 linii (25 dat na pasek ruchu), ale użyliśmy do tego tylko 4 wierszy, co ułatwia wszystkim innym reprodukcję bez kopiowania i wklejania 100 linii kodu. Następnie możesz wyświetlić podzbiory danych, jeśli pomoże to wyjaśnić pytanie:

>>> stocks.head(5)

        date      price ticker
0 2011-01-01   9.497412   aapl
1 2011-01-02  10.261908   aapl
2 2011-01-03   9.438538   aapl
3 2011-01-04   9.515958   aapl
4 2011-01-05   7.554070   aapl

>>> stocks.groupby('ticker').head(2)

         date      price ticker
0  2011-01-01   9.497412   aapl
1  2011-01-02  10.261908   aapl
25 2011-01-01   8.277772   goog
26 2011-01-02   7.714916   goog
50 2011-01-01   5.613023   yhoo
51 2011-01-02   6.397686   yhoo
75 2011-01-01  11.736584   msft
76 2011-01-02  11.944519   msft
51 piRSquared Jul 20 2016 at 01:35

Diary of an Answerer

Moją najlepszą radą przy zadawaniu pytań byłoby granie na psychologii ludzi, którzy odpowiadają na pytania. Będąc jedną z tych osób, mogę wyjaśnić, dlaczego odpowiadam na niektóre pytania, a na inne nie.

Motywacje

Jestem zmotywowany do odpowiadania na pytania z kilku powodów

  1. Stackoverflow.com był dla mnie niezwykle cennym źródłem informacji. Chciałem oddać.
  2. W moich wysiłkach, aby się odwdzięczyć, odkryłem, że ta witryna jest jeszcze potężniejszym źródłem niż wcześniej. Odpowiadanie na pytania to dla mnie nauka i lubię się uczyć. Przeczytaj tę odpowiedź i komentarz od innego weterynarza . Ten rodzaj interakcji mnie uszczęśliwia.
  3. Lubię punkty!
  4. Zobacz nr 3.
  5. Lubię ciekawe problemy.

Wszystkie moje najczystsze intencje są wielkie i wszystkie, ale czerpię satysfakcję, jeśli odpowiem na 1 pytanie lub 30. To, co kieruje moimi wyborami, na które mam odpowiedzieć, ma ogromny składnik maksymalizacji punktów.

Spędzę też czas na interesujących problemach, ale jest ich niewiele i nie pomoże pytającemu, który potrzebuje rozwiązania nieinteresującego pytania. Najlepszym sposobem, aby skłonić mnie do odpowiedzi na pytanie, jest zaserwowanie tego pytania na tacy, na której mogę odpowiedzieć przy jak najmniejszym wysiłku. Jeśli patrzę na dwa pytania, a jedno ma kod, mogę skopiować wklej, aby utworzyć wszystkie potrzebne mi zmienne ... Biorę to! Wrócę do tego drugiego, jeśli będę miał czas.

Główna rada

Ułatw ludziom odpowiadanie na pytania.

  • Podaj kod, który tworzy potrzebne zmienne.
  • Zminimalizuj ten kod. Jeśli moje oczy błyszczą, gdy patrzę na wpis, przechodzę do następnego pytania lub wracam do tego, co robię.
  • Zastanów się, o co pytasz i bądź konkretny. Chcemy zobaczyć, co zrobiłeś, ponieważ języki naturalne (angielski) są niedokładne i zagmatwane. Próbki kodu tego, co wypróbowałeś, pomagają rozwiązać niespójności w opisie w języku naturalnym.
  • PROSZĘ pokazać, czego oczekujesz !!! Muszę usiąść i spróbować różnych rzeczy. Prawie nigdy nie znam odpowiedzi na pytanie bez wypróbowania kilku rzeczy. Jeśli nie widzę przykładu tego, czego szukasz, mogę przekazać pytanie, ponieważ nie mam ochoty zgadywać.

Twoja reputacja to coś więcej niż tylko reputacja.

Lubię punkty (wspomniałem o tym powyżej). Ale te punkty nie są tak naprawdę moją reputacją. Moja prawdziwa reputacja jest połączeniem tego, co myślą o mnie inni użytkownicy witryny. Staram się być uczciwy i uczciwy i mam nadzieję, że inni to dostrzegają. Dla pytającego oznacza to, że pamiętamy zachowania pytających. Jeśli nie wybierasz odpowiedzi i nie głosujesz pozytywnie, to pamiętam. Pamiętam, jeśli zachowujesz się w sposób, który mi się nie podoba lub mi się podoba. Dotyczy to również pytań, na które odpowiem.


W każdym razie, prawdopodobnie mogę kontynuować, ale oszczędzę was wszystkich, którzy faktycznie to czytali.

31 Alexander Sep 12 2015 at 14:06

Wyzwanie Jednym z najtrudniejszych aspektów odpowiadania na pytania SO jest czas potrzebny na odtworzenie problemu (w tym danych). Odpowiedzi na pytania, które nie mają jasnego sposobu odtworzenia danych, są mniej prawdopodobne. Biorąc pod uwagę, że poświęcasz czas na napisanie pytania i masz problem, z którym chciałbyś uzyskać pomoc, możesz łatwo pomóc sobie, dostarczając dane, które inni mogą następnie wykorzystać do rozwiązania Twojego problemu.

Instrukcje podane przez @Andy dotyczące pisania dobrych pytań o Pandy są doskonałym miejscem do rozpoczęcia. Aby uzyskać więcej informacji, zobacz, jak zadawać pytania i jak tworzyć przykłady minimalne, kompletne i weryfikowalne .

Prosimy o wyraźne sformułowanie pytania z góry. Po poświęceniu czasu na napisanie pytania i przykładowego kodu, spróbuj je przeczytać i dostarczyć czytelnikowi „Streszczenie”, które podsumowuje problem i jasno określa pytanie.

Oryginalne pytanie :

Mam te dane ...

Chce to zrobić...

Chcę, żeby mój wynik wyglądał tak ...

Jednak kiedy próbuję to zrobić, pojawia się następujący problem ...

Próbowałem znaleźć rozwiązania, robiąc [to] i [tamto].

Jak to naprawić?

W zależności od ilości danych, przykładowego kodu i dostarczonych stosów błędów, czytelnik musi przejść długą drogę, zanim zrozumie, na czym polega problem. Spróbuj powtórzyć pytanie, tak aby samo pytanie znajdowało się na górze, a następnie podaj niezbędne szczegóły.

Poprawione pytanie :

Pytanie: Jak mogę to zrobić?

Próbowałem znaleźć rozwiązania, robiąc [to] i [tamto].

Kiedy próbuję to zrobić, pojawia się następujący problem ...

Chciałbym, żeby moje ostateczne wyniki wyglądały tak ...

Oto minimalny kod, który może odtworzyć mój problem ...

A oto jak odtworzyć moje przykładowe dane: df = pd.DataFrame({'A': [...], 'B': [...], ...})

PODAJ PRZYKŁADOWE DANE, JEŚLI POTRZEBNE !!!

Czasami wystarczy tylko początek lub koniec ramki DataFrame. Możesz także użyć metod zaproponowanych przez @JohnE do tworzenia większych zbiorów danych, które mogą być odtwarzane przez innych. Na jego przykładzie wygeneruj ramkę danych DataFrame zawierającą 100 wierszy:

stocks = pd.DataFrame({ 
    'ticker':np.repeat( ['aapl','goog','yhoo','msft'], 25 ),
    'date':np.tile( pd.date_range('1/1/2011', periods=25, freq='D'), 4 ),
    'price':(np.random.randn(100).cumsum() + 10) })

Jeśli to były twoje rzeczywiste dane, możesz po prostu dołączyć nagłówek i / lub koniec ramki danych w następujący sposób (pamiętaj o anonimizacji wszelkich danych wrażliwych):

>>> stocks.head(5).to_dict()
{'date': {0: Timestamp('2011-01-01 00:00:00'),
  1: Timestamp('2011-01-01 00:00:00'),
  2: Timestamp('2011-01-01 00:00:00'),
  3: Timestamp('2011-01-01 00:00:00'),
  4: Timestamp('2011-01-02 00:00:00')},
 'price': {0: 10.284260107718254,
  1: 11.930300761831457,
  2: 10.93741046217319,
  3: 10.884574289565609,
  4: 11.78005850418319},
 'ticker': {0: 'aapl', 1: 'aapl', 2: 'aapl', 3: 'aapl', 4: 'aapl'}}

>>> pd.concat([stocks.head(), stocks.tail()], ignore_index=True).to_dict()
{'date': {0: Timestamp('2011-01-01 00:00:00'),
  1: Timestamp('2011-01-01 00:00:00'),
  2: Timestamp('2011-01-01 00:00:00'),
  3: Timestamp('2011-01-01 00:00:00'),
  4: Timestamp('2011-01-02 00:00:00'),
  5: Timestamp('2011-01-24 00:00:00'),
  6: Timestamp('2011-01-25 00:00:00'),
  7: Timestamp('2011-01-25 00:00:00'),
  8: Timestamp('2011-01-25 00:00:00'),
  9: Timestamp('2011-01-25 00:00:00')},
 'price': {0: 10.284260107718254,
  1: 11.930300761831457,
  2: 10.93741046217319,
  3: 10.884574289565609,
  4: 11.78005850418319,
  5: 10.017209045035006,
  6: 10.57090128181566,
  7: 11.442792747870204,
  8: 11.592953372130493,
  9: 12.864146419530938},
 'ticker': {0: 'aapl',
  1: 'aapl',
  2: 'aapl',
  3: 'aapl',
  4: 'aapl',
  5: 'msft',
  6: 'msft',
  7: 'msft',
  8: 'msft',
  9: 'msft'}}

Możesz również podać opis ramki DataFrame (używając tylko odpowiednich kolumn). Ułatwia to innym sprawdzanie typów danych w każdej kolumnie i identyfikowanie innych typowych błędów (np. Daty jako ciąg znaków, a datetime64 i obiekt):

stocks.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 100 entries, 0 to 99
Data columns (total 3 columns):
date      100 non-null datetime64[ns]
price     100 non-null float64
ticker    100 non-null object
dtypes: datetime64[ns](1), float64(1), object(1)

UWAGA: Jeśli Twoja ramka DataFrame ma MultiIndex:

Jeśli Twoja ramka DataFrame ma multiindeks, musisz najpierw zresetować ją przed wywołaniem to_dict. Następnie musisz ponownie utworzyć indeks za pomocą set_index:

# MultiIndex example.  First create a MultiIndex DataFrame.
df = stocks.set_index(['date', 'ticker'])
>>> df
                       price
date       ticker           
2011-01-01 aapl    10.284260
           aapl    11.930301
           aapl    10.937410
           aapl    10.884574
2011-01-02 aapl    11.780059
...

# After resetting the index and passing the DataFrame to `to_dict`, make sure to use 
# `set_index` to restore the original MultiIndex.  This DataFrame can then be restored.

d = df.reset_index().to_dict()
df_new = pd.DataFrame(d).set_index(['date', 'ticker'])
>>> df_new.head()
                       price
date       ticker           
2011-01-01 aapl    10.284260
           aapl    11.930301
           aapl    10.937410
           aapl    10.884574
2011-01-02 aapl    11.780059
15 sds Dec 17 2016 at 00:57

Oto moja wersja dput- standardowego narzędzia R do tworzenia powtarzalnych raportów - dla Pand DataFrame. Prawdopodobnie zawiedzie w przypadku bardziej złożonych ramek, ale wydaje się, że działa w prostych przypadkach:

import pandas as pd
def dput(x):
    if isinstance(x,pd.Series):
        return "pd.Series(%s,dtype='%s',index=pd.%s)" % (list(x),x.dtype,x.index)
    if isinstance(x,pd.DataFrame):
        return "pd.DataFrame({" + ", ".join([
            "'%s': %s" % (c,dput(x[c])) for c in x.columns]) + (
                "}, index=pd.%s)" % (x.index))
    raise NotImplementedError("dput",type(x),x)

teraz,

df = pd.DataFrame({'a':[1,2,3,4,2,1,3,1]})
assert df.equals(eval(dput(df)))
du = pd.get_dummies(df.a,"foo")
assert du.equals(eval(dput(du)))
di = df
di.index = list('abcdefgh')
assert di.equals(eval(dput(di)))

Zauważ, że daje to dużo bardziej szczegółowe dane wyjściowe niż DataFrame.to_dictnp.

pd.DataFrame({
  'foo_1':pd.Series([1, 0, 0, 0, 0, 1, 0, 1],dtype='uint8',index=pd.RangeIndex(start=0, stop=8, step=1)),
  'foo_2':pd.Series([0, 1, 0, 0, 1, 0, 0, 0],dtype='uint8',index=pd.RangeIndex(start=0, stop=8, step=1)),
  'foo_3':pd.Series([0, 0, 1, 0, 0, 0, 1, 0],dtype='uint8',index=pd.RangeIndex(start=0, stop=8, step=1)),
  'foo_4':pd.Series([0, 0, 0, 1, 0, 0, 0, 0],dtype='uint8',index=pd.RangeIndex(start=0, stop=8, step=1))},
  index=pd.RangeIndex(start=0, stop=8, step=1))

vs

{'foo_1': {0: 1, 1: 0, 2: 0, 3: 0, 4: 0, 5: 1, 6: 0, 7: 1}, 
 'foo_2': {0: 0, 1: 1, 2: 0, 3: 0, 4: 1, 5: 0, 6: 0, 7: 0}, 
 'foo_3': {0: 0, 1: 0, 2: 1, 3: 0, 4: 0, 5: 0, 6: 1, 7: 0}, 
 'foo_4': {0: 0, 1: 0, 2: 0, 3: 1, 4: 0, 5: 0, 6: 0, 7: 0}}

do dupowyżej, ale zachowuje typy kolumn . Np. W powyższym przypadku testowym

du.equals(pd.DataFrame(du.to_dict()))
==> False

ponieważ du.dtypesjest uint8i pd.DataFrame(du.to_dict()).dtypesjest int64.