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.