Konwertuj ramkę danych pandy na tablicę NumPy


465

Jestem zainteresowany wiedzą, jak przekonwertować ramkę danych pandy na tablicę NumPy.

ramka danych:

import numpy as np
import pandas as pd

index = [1, 2, 3, 4, 5, 6, 7]
a = [np.nan, np.nan, np.nan, 0.1, 0.1, 0.1, 0.1]
b = [0.2, np.nan, 0.2, 0.2, 0.2, np.nan, np.nan]
c = [np.nan, 0.5, 0.5, np.nan, 0.5, 0.5, np.nan]
df = pd.DataFrame({'A': a, 'B': b, 'C': c}, index=index)
df = df.rename_axis('ID')

daje

label   A    B    C
ID                                 
1   NaN  0.2  NaN
2   NaN  NaN  0.5
3   NaN  0.2  0.5
4   0.1  0.2  NaN
5   0.1  0.2  0.5
6   0.1  NaN  0.5
7   0.1  NaN  NaN

Chciałbym przekonwertować to na tablicę NumPy, ponieważ:

array([[ nan,  0.2,  nan],
       [ nan,  nan,  0.5],
       [ nan,  0.2,  0.5],
       [ 0.1,  0.2,  nan],
       [ 0.1,  0.2,  0.5],
       [ 0.1,  nan,  0.5],
       [ 0.1,  nan,  nan]])

W jaki sposób mogę to zrobić?


Jako bonus, czy możliwe jest zachowanie takich typów, jak ten?

array([[ 1, nan,  0.2,  nan],
       [ 2, nan,  nan,  0.5],
       [ 3, nan,  0.2,  0.5],
       [ 4, 0.1,  0.2,  nan],
       [ 5, 0.1,  0.2,  0.5],
       [ 6, 0.1,  nan,  0.5],
       [ 7, 0.1,  nan,  nan]],
     dtype=[('ID', '<i4'), ('A', '<f8'), ('B', '<f8'), ('B', '<f8')])

lub podobne?


5
Dlaczego tego potrzebujesz? Czy i tak ramki danych nie są oparte na tablicach numpy? Powinieneś być w stanie użyć ramki danych, w której potrzebujesz tablicy numpy. Dlatego możesz używać ramek danych w scikit-learn, gdzie funkcje proszą o tablice numpy.
— chrisfs

Oto kilka potencjalnie odpowiednich linków na temat dtypów i recarrays (aka tablic rekordów lub tablic strukturalnych): (1) stackoverflow.com/questions/9949427/… (2) stackoverflow.com/questions/52579601/...
— JohnE

UWAGA: Konieczność konwersji Pandas DataFrame na tablicę (lub listę) w ten sposób może wskazywać na inne problemy. Zdecydowanie zalecam upewnienie się, że DataFrame jest odpowiednią strukturą danych dla konkretnego przypadku użycia i że Pandas nie zawiera żadnego sposobu wykonywania operacji, którymi jesteś zainteresowany.
— AMC

Odpowiedzi:


390

Aby przekonwertować ramkę danych pandy (df) na numeryczną ndarray, użyj tego kodu:

df.values

array([[nan, 0.2, nan],
       [nan, nan, 0.5],
       [nan, 0.2, 0.5],
       [0.1, 0.2, nan],
       [0.1, 0.2, 0.5],
       [0.1, nan, 0.5],
       [0.1, nan, nan]])

237

Przestań używać valuesi as_matrix()!

panda v0.24.0 wprowadziła dwie nowe metody uzyskiwania tablic NumPy z obiektów pand:

  1. to_numpy(), Który jest zdefiniowany Index, Series,i DataFrameobiektów, a
  2. array, który jest zdefiniowany Indexi dotyczy Seriestylko obiektów.

Jeśli odwiedzisz dokumentację v0.24 .values, zobaczysz duże czerwone ostrzeżenie z napisem:

Ostrzeżenie: zalecamy użycie DataFrame.to_numpy()zamiast tego.

Więcej informacji można znaleźć w tej sekcji informacji o wersji v0.24.0 i w tej odpowiedzi .


W kierunku lepszej spójności: to_numpy()

W duchu lepszej spójności w całym interfejsie API wprowadzono nową metodę to_numpywydobywania bazowej tablicy NumPy z DataFrames.

# Setup.
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]}, index=['a', 'b', 'c'])

df.to_numpy()
array([[1, 4],
       [2, 5],
       [3, 6]])

Jak wspomniano powyżej, ta metoda jest również zdefiniowana w obiektach Indexi Seriesobiektach (patrz tutaj ).

df.index.to_numpy()
# array(['a', 'b', 'c'], dtype=object)

df['A'].to_numpy()
#  array([1, 2, 3])

Domyślnie widok jest zwracany, więc wszelkie dokonane modyfikacje wpłyną na oryginał.

v = df.to_numpy()
v[0, 0] = -1

df
   A  B
a -1  4
b  2  5
c  3  6

Jeśli zamiast tego potrzebujesz kopii, użyj to_numpy(copy=True).

panda> = aktualizacja 1.0 dla ExtensionTypes

Jeśli używasz pand 1.x, prawdopodobnie będziesz miał do czynienia z typami rozszerzeń o wiele więcej. Musisz być trochę bardziej ostrożny, aby te typy rozszerzeń zostały poprawnie przekonwertowane.

a = pd.array([1, 2, None], dtype="Int64")                                  
a                                                                          

<IntegerArray>
[1, 2, <NA>]
Length: 3, dtype: Int64 

# Wrong
a.to_numpy()                                                               
# array([1, 2, <NA>], dtype=object)  # yuck, objects

# Right
a.to_numpy(dtype='float', na_value=np.nan)                                 
# array([ 1.,  2., nan])

Jest to przywołane w dokumentach .

Jeśli potrzebujesz dtypes...

Jak pokazano w innej odpowiedzi, DataFrame.to_recordsjest to dobry sposób na zrobienie tego.

df.to_records()
# rec.array([('a', -1, 4), ('b',  2, 5), ('c',  3, 6)],
#           dtype=[('index', 'O'), ('A', '<i8'), ('B', '<i8')])

to_numpyNiestety nie da się tego zrobić . Alternatywnie możesz użyć np.rec.fromrecords:

v = df.reset_index()
np.rec.fromrecords(v, names=v.columns.tolist())
# rec.array([('a', -1, 4), ('b',  2, 5), ('c',  3, 6)],
#          dtype=[('index', '<U1'), ('A', '<i8'), ('B', '<i8')])

Pod względem wydajności jest prawie taki sam (w rzeczywistości korzystanie rec.fromrecordsjest nieco szybsze).

df2 = pd.concat([df] * 10000)

%timeit df2.to_records()
%%timeit
v = df2.reset_index()
np.rec.fromrecords(v, names=v.columns.tolist())

11.1 ms ± 557 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
9.67 ms ± 126 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Uzasadnienie dodania nowej metody

to_numpy()(oprócz array) dodano w wyniku dyskusji na temat dwóch zagadnień GitHub: GH19954 i GH23623 .

W szczególności dokumenty wspominają o uzasadnieniu:

[...] .valuesnie było jasne, czy zwrócona wartość będzie rzeczywistą tablicą, jakąś jej transformacją, czy jedną z niestandardowych tablic pand (jak Categorical). Na przykład, z PeriodIndex, .values generuje nowy ndarrayokresu obiektów za każdym razem. [...]

to_numpydążyć do poprawy spójności interfejsu API, co stanowi duży krok we właściwym kierunku. .valuesnie będzie przestarzałe w bieżącej wersji, ale spodziewam się, że tak się stanie w przyszłości, więc zachęcam użytkowników do migracji w kierunku nowszego interfejsu API, tak szybko, jak to możliwe.


Krytyka innych rozwiązań

DataFrame.values ma niespójne zachowanie, jak już wspomniano.

DataFrame.get_values()to po prostu opakowanie DataFrame.values, więc wszystko, co powiedziano powyżej, ma zastosowanie.

DataFrame.as_matrix()jest przestarzałe, NIE używaj!


Nie rozumiem, jak można czytać strona po stronie po stronie ludzi krzyczących u góry ich płuc, aby przejść z as_matrixinnego rozwiązania, w tym przypadku to_numpybez wyjaśnienia, jak odzyskać funkcjonalność wyboru kolumny as_matrix! Jestem pewien, że istnieją inne sposoby wyboru kolumn, ale as_matrixbył przynajmniej jeden z nich!
— Jérémie

@ Jérémie oprócz oczywistości df[[col1, col2']].to_numpy()? Nie wiem, dlaczego uważasz, że chcesz zareklamować zaktualizowaną alternatywę dla przestarzałej funkcji, uzasadnia odpowiedź negatywną na odpowiedź.
— cs95

co jeśli niektóre kolumny są typu listy. Jak mogę stworzyć z tego płaską wyboistą tablicę?
— Moniba

@Moniba możesz rozłożyć elementy listy na osobne kolumny / wiersze zgodnie z wymaganiami.
— cs95

O ile się nie mylę, uzyskanie więcej niż jednej kolumny w tym samym wywołaniu powoduje scalenie wszystkich danych w jedną dużą tablicę. Czy coś brakuje?
— Andrea Moro

128

Uwaga : .as_matrix()metoda zastosowana w tej odpowiedzi jest przestarzała. Panda 0.23.4 ostrzega:

Metoda .as_matrixzostanie usunięta w przyszłej wersji. Zamiast tego użyj .values.


Pandy mają coś wbudowanego ...

numpy_matrix = df.as_matrix()

daje

array([[nan, 0.2, nan],
       [nan, nan, 0.5],
       [nan, 0.2, 0.5],
       [0.1, 0.2, nan],
       [0.1, 0.2, 0.5],
       [0.1, nan, 0.5],
       [0.1, nan, nan]])

30
Nie daje to tablicy strukturalnej, wszystkie kolumny są typu dtype object.
— sebix,

14
„Przestarzałe od wersji 0.23.0: Zamiast tego należy użyć DataFrame.values.” / „Ta metoda zapewnia zgodność wsteczną. Ogólnie zaleca się stosowanie„ .values ​​”.” - github.com/pandas-dev/pandas/blob/…
— David J.

4
To jest teraz przestarzałe. Począwszy od wersji 0.24, używaj to_numpyzamiast tego (nie .valuesalbo). Więcej tutaj .
— cs95

1
„FutureWarning: Metoda .as_matrix zostanie usunięta w przyszłej wersji. Zamiast tego użyj .values.”
— Farhad Maleki

66

Po prostu połączę funkcje DataFrame.reset_index () i DataFrame.values, aby uzyskać reprezentację Numpy ramki danych, w tym indeksu:

In [8]: df
Out[8]: 
          A         B         C
0 -0.982726  0.150726  0.691625
1  0.617297 -0.471879  0.505547
2  0.417123 -1.356803 -1.013499
3 -0.166363 -0.957758  1.178659
4 -0.164103  0.074516 -0.674325
5 -0.340169 -0.293698  1.231791
6 -1.062825  0.556273  1.508058
7  0.959610  0.247539  0.091333

[8 rows x 3 columns]

In [9]: df.reset_index().values
Out[9]:
array([[ 0.        , -0.98272574,  0.150726  ,  0.69162512],
       [ 1.        ,  0.61729734, -0.47187926,  0.50554728],
       [ 2.        ,  0.4171228 , -1.35680324, -1.01349922],
       [ 3.        , -0.16636303, -0.95775849,  1.17865945],
       [ 4.        , -0.16410334,  0.0745164 , -0.67432474],
       [ 5.        , -0.34016865, -0.29369841,  1.23179064],
       [ 6.        , -1.06282542,  0.55627285,  1.50805754],
       [ 7.        ,  0.95961001,  0.24753911,  0.09133339]])

Aby uzyskać typy, musielibyśmy przekształcić tę tablicę ndarray w tablicę strukturalną za pomocą widoku :

In [10]: df.reset_index().values.ravel().view(dtype=[('index', int), ('A', float), ('B', float), ('C', float)])
Out[10]:
array([( 0, -0.98272574,  0.150726  ,  0.69162512),
       ( 1,  0.61729734, -0.47187926,  0.50554728),
       ( 2,  0.4171228 , -1.35680324, -1.01349922),
       ( 3, -0.16636303, -0.95775849,  1.17865945),
       ( 4, -0.16410334,  0.0745164 , -0.67432474),
       ( 5, -0.34016865, -0.29369841,  1.23179064),
       ( 6, -1.06282542,  0.55627285,  1.50805754),
       ( 7,  0.95961001,  0.24753911,  0.09133339),
       dtype=[('index', '<i8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')])

3
jedyne, czego brakuje w tej odpowiedzi, to jak zbudować typ z ramki danych, aby można było napisać funkcję ogólną
— Joseph Garvin

32

Możesz użyć tej to_recordsmetody, ale musisz się trochę pobawić z typami dtypów, jeśli od samego początku nie są to, czego chcesz. W moim przypadku po skopiowaniu pliku DF z łańcucha typ indeksu to ciąg (reprezentowany przez objectdtype w pandach):

In [102]: df
Out[102]: 
label    A    B    C
ID                  
1      NaN  0.2  NaN
2      NaN  NaN  0.5
3      NaN  0.2  0.5
4      0.1  0.2  NaN
5      0.1  0.2  0.5
6      0.1  NaN  0.5
7      0.1  NaN  NaN

In [103]: df.index.dtype
Out[103]: dtype('object')
In [104]: df.to_records()
Out[104]: 
rec.array([(1, nan, 0.2, nan), (2, nan, nan, 0.5), (3, nan, 0.2, 0.5),
       (4, 0.1, 0.2, nan), (5, 0.1, 0.2, 0.5), (6, 0.1, nan, 0.5),
       (7, 0.1, nan, nan)], 
      dtype=[('index', '|O8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')])
In [106]: df.to_records().dtype
Out[106]: dtype([('index', '|O8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')])

Konwersja typu recarray dtype nie działa dla mnie, ale można to zrobić już w Pandach:

In [109]: df.index = df.index.astype('i8')
In [111]: df.to_records().view([('ID', '<i8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')])
Out[111]:
rec.array([(1, nan, 0.2, nan), (2, nan, nan, 0.5), (3, nan, 0.2, 0.5),
       (4, 0.1, 0.2, nan), (5, 0.1, 0.2, 0.5), (6, 0.1, nan, 0.5),
       (7, 0.1, nan, nan)], 
      dtype=[('ID', '<i8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')])

Zauważ, że Panda nie ustawia poprawnie nazwy indeksu (do ID) w eksportowanej tablicy rekordów (błąd?), Więc korzystamy z konwersji typu, aby również to poprawić.

W tej chwili Pandy mają tylko 8-bajtowe liczby całkowite i8i są zmiennoprzecinkowe f8(patrz ten problem ).


2
Aby uzyskać poszukiwaną tablicę strukturalną (która ma lepszą wydajność niż recarray), wystarczy przekazać ją do np.arraykonstruktora.
— meteore

Właśnie wprowadziliśmy poprawkę do ustawiania nazwy indeksu pokazanej powyżej.
— Chang She

26

Wygląda na to, df.to_records()że zadziała dla ciebie. Dokładna funkcja, której szukasz, została poproszona i to_recordswskazana jako alternatywa.

Wypróbowałem to lokalnie na twoim przykładzie, a to wywołanie daje coś bardzo podobnego do wyjścia, którego szukałeś:

rec.array([(1, nan, 0.2, nan), (2, nan, nan, 0.5), (3, nan, 0.2, 0.5),
       (4, 0.1, 0.2, nan), (5, 0.1, 0.2, 0.5), (6, 0.1, nan, 0.5),
       (7, 0.1, nan, nan)],
      dtype=[(u'ID', '<i8'), (u'A', '<f8'), (u'B', '<f8'), (u'C', '<f8')])

Zauważ, że jest to recarrayraczej niż array. Możesz przenieść wynik do zwykłej tablicy numpy, wywołując jej konstruktor jako np.array(df.to_records()).


3
Zaraz, co dodaje ta odpowiedź w porównaniu z inną odpowiedzią @meteore, o której wspominano to_records()5 lat wcześniej?
— JohnE,

13

Spróbuj tego:

a = numpy.asarray(df)

Cześć! Dodaj wyjaśnienie do swojej odpowiedzi. W tej chwili jest on oznaczany jako niskiej jakości przez przegląd ze względu na długość i treść i istnieje ryzyko, że zostanie usunięty przez system. Dzięki!
— d_kennetz

1
po prostu przekonwertuj dane wejściowe na tablicę (jak sama nazwa wskazuje). Tak więc wraz z kontekstem pytania ta odpowiedź jest ważna. sprawdź docs.scipy.org/doc/numpy/reference/generated/…
— Lautaro Parada Opazo

Dzięki, myślę, że to trochę oczywiste.
— Dadu Khan

8

Oto moje podejście do tworzenia tablicy struktur z pand DataFrame.

Utwórz ramkę danych

import pandas as pd
import numpy as np
import six

NaN = float('nan')
ID = [1, 2, 3, 4, 5, 6, 7]
A = [NaN, NaN, NaN, 0.1, 0.1, 0.1, 0.1]
B = [0.2, NaN, 0.2, 0.2, 0.2, NaN, NaN]
C = [NaN, 0.5, 0.5, NaN, 0.5, 0.5, NaN]
columns = {'A':A, 'B':B, 'C':C}
df = pd.DataFrame(columns, index=ID)
df.index.name = 'ID'
print(df)

      A    B    C
ID               
1   NaN  0.2  NaN
2   NaN  NaN  0.5
3   NaN  0.2  0.5
4   0.1  0.2  NaN
5   0.1  0.2  0.5
6   0.1  NaN  0.5
7   0.1  NaN  NaN

Zdefiniuj funkcję, aby utworzyć tablicę struktury numpy (nie tablicę rekordów) z pandy DataFrame.

def df_to_sarray(df):
    """
    Convert a pandas DataFrame object to a numpy structured array.
    This is functionally equivalent to but more efficient than
    np.array(df.to_array())

    :param df: the data frame to convert
    :return: a numpy structured array representation of df
    """

    v = df.values
    cols = df.columns

    if six.PY2:  # python 2 needs .encode() but 3 does not
        types = [(cols[i].encode(), df[k].dtype.type) for (i, k) in enumerate(cols)]
    else:
        types = [(cols[i], df[k].dtype.type) for (i, k) in enumerate(cols)]
    dtype = np.dtype(types)
    z = np.zeros(v.shape[0], dtype)
    for (i, k) in enumerate(z.dtype.names):
        z[k] = v[:, i]
    return z

Służy reset_indexdo tworzenia nowej ramki danych zawierającej indeks jako część jego danych. Konwertuj tę ramkę danych na tablicę struktur.

sa = df_to_sarray(df.reset_index())
sa

array([(1L, nan, 0.2, nan), (2L, nan, nan, 0.5), (3L, nan, 0.2, 0.5),
       (4L, 0.1, 0.2, nan), (5L, 0.1, 0.2, 0.5), (6L, 0.1, nan, 0.5),
       (7L, 0.1, nan, nan)], 
      dtype=[('ID', '<i8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')])

EDYCJA: Zaktualizowano df_to_sarray, aby uniknąć błędu wywołania .encode () w Pythonie 3. Dziękujemy Josephowi Garvinowi i halcyonowi za komentarz i rozwiązanie.


nie działa dla mnie, błąd: TypeError: typ danych niezrozumiany
— Joseph Garvin

Dzięki za komentarz i halcyon za korektę. Zaktualizowałem swoją odpowiedź, więc mam nadzieję, że teraz zadziała.
— Phil,


5

Prostszy sposób na przykład DataFrame:

df

         gbm       nnet        reg
0  12.097439  12.047437  12.100953
1  12.109811  12.070209  12.095288
2  11.720734  11.622139  11.740523
3  11.824557  11.926414  11.926527
4  11.800868  11.727730  11.729737
5  12.490984  12.502440  12.530894

POSŁUGIWAĆ SIĘ:

np.array(df.to_records().view(type=np.matrix))

DOSTAĆ:

array([[(0, 12.097439  , 12.047437, 12.10095324),
        (1, 12.10981081, 12.070209, 12.09528824),
        (2, 11.72073428, 11.622139, 11.74052253),
        (3, 11.82455653, 11.926414, 11.92652727),
        (4, 11.80086775, 11.72773 , 11.72973699),
        (5, 12.49098389, 12.50244 , 12.53089367)]],
dtype=(numpy.record, [('index', '<i8'), ('gbm', '<f8'), ('nnet', '<f4'),
       ('reg', '<f8')]))

4

Miałem podobny problem podczas eksportowania z ramki danych do tabeli arcgis i natknąłem się na rozwiązanie z usgs ( https://my.usgs.gov/confluence/display/cdi/pandas.DataFrame+to+ArcGIS+Table ). Krótko mówiąc, twój problem ma podobne rozwiązanie:

df

      A    B    C
ID               
1   NaN  0.2  NaN
2   NaN  NaN  0.5
3   NaN  0.2  0.5
4   0.1  0.2  NaN
5   0.1  0.2  0.5
6   0.1  NaN  0.5
7   0.1  NaN  NaN

np_data = np.array(np.rec.fromrecords(df.values))
np_names = df.dtypes.index.tolist()
np_data.dtype.names = tuple([name.encode('UTF8') for name in np_names])

np_data

array([( nan,  0.2,  nan), ( nan,  nan,  0.5), ( nan,  0.2,  0.5),
       ( 0.1,  0.2,  nan), ( 0.1,  0.2,  0.5), ( 0.1,  nan,  0.5),
       ( 0.1,  nan,  nan)], 
      dtype=(numpy.record, [('A', '<f8'), ('B', '<f8'), ('C', '<f8')]))

4

Przejrzałem powyższe odpowiedzi. Metoda „ as_matrix () ” działa, ale jest już przestarzała. Dla mnie zadziałało „ .to_numpy () ”.

Zwraca tablicę wielowymiarową. Wolę używać tej metody, jeśli czytasz dane z arkusza programu Excel i potrzebujesz dostępu do danych z dowolnego indeksu. Mam nadzieję że to pomoże :)


Co masz na myśli i potrzebujesz dostępu do danych z dowolnego indeksu ? W zależności od charakteru twoich danych, Pandas DataFrame może nawet nie być właściwym wyborem.
— AMC

2

Po odpowiedzi meteora znalazłem kod

df.index = df.index.astype('i8')

nie działa dla mnie Dlatego umieściłem tutaj swój kod dla wygody innych osób, które borykają się z tym problemem.

city_cluster_df = pd.read_csv(text_filepath, encoding='utf-8')
# the field 'city_en' is a string, when converted to Numpy array, it will be an object
city_cluster_arr = city_cluster_df[['city_en','lat','lon','cluster','cluster_filtered']].to_records()
descr=city_cluster_arr.dtype.descr
# change the field 'city_en' to string type (the index for 'city_en' here is 1 because before the field is the row index of dataframe)
descr[1]=(descr[1][0], "S20")
newArr=city_cluster_arr.astype(np.dtype(descr))

1

Prosty sposób na konwersję ramki danych na tablicę numpy:

import pandas as pd
df = pd.DataFrame({"A": [1, 2], "B": [3, 4]})
df_to_array = df.to_numpy()
array([[1, 3],
   [2, 4]])

Zalecane jest używanie to_numpy w celu zachowania spójności.

Odniesienie: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_numpy.html


jaka jest różnica między rozwiązaniem dostarczonym przez Arsam a twoim ...
— qaiser

Po prostu starałem się uczynić go bardziej kompletnym i użytecznym na przykładzie kodu, co osobiście wolę.
— user1460675,

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.