Znajdź maksymalnie dwie lub więcej kolumn z pandami

105

Mam dataframe z kolumnami A, B. Muszę utworzyć taką kolumnę C, aby dla każdego rekordu / wiersza:

C = max(A, B).

Jak mam się do tego zabrać?

Navneet
źródło

Odpowiedzi:

198

Możesz uzyskać maksimum w ten sposób:

>>> import pandas as pd
>>> df = pd.DataFrame({"A": [1,2,3], "B": [-2, 8, 1]})
>>> df
   A  B
0  1 -2
1  2  8
2  3  1
>>> df[["A", "B"]]
   A  B
0  1 -2
1  2  8
2  3  1
>>> df[["A", "B"]].max(axis=1)
0    1
1    8
2    3

a więc:

>>> df["C"] = df[["A", "B"]].max(axis=1)
>>> df
   A  B  C
0  1 -2  1
1  2  8  8
2  3  1  3

Jeśli wiesz, że „A” i „B” to jedyne kolumny, możesz nawet uciec

>>> df["C"] = df.max(axis=1)

I .apply(max, axis=1)myślę, że ty też możesz użyć .

DSM
źródło
2
.apply(max, axis=1)jest znacznie wolniejszy niż.max(axis=1)
RajeshM
30

Odpowiedź @ DSM jest w porządku w prawie każdym normalnym scenariuszu. Ale jeśli jesteś typem programisty, który chce wejść trochę głębiej niż poziom powierzchniowy, możesz być zainteresowany, aby wiedzieć, że trochę szybciej jest wywoływać funkcje numpy na bazowej .to_numpy()(lub .values<0,24) tablicy zamiast bezpośrednio wywoływanie (cytonizowanych) funkcji zdefiniowanych w obiektach DataFrame / Series.

Na przykład możesz użyć ndarray.max()wzdłuż pierwszej osi.

# Data borrowed from @DSM's post.
df = pd.DataFrame({"A": [1,2,3], "B": [-2, 8, 1]})
df
   A  B
0  1 -2
1  2  8
2  3  1

df['C'] = df[['A', 'B']].values.max(1)
# Or, assuming "A" and "B" are the only columns, 
# df['C'] = df.values.max(1) 
df

   A  B  C
0  1 -2  1
1  2  8  8
2  3  1  3 

Jeśli Twoje dane mają NaNs, będziesz potrzebować numpy.nanmax:

df['C'] = np.nanmax(df.values, axis=1)
df

   A  B  C
0  1 -2  1
1  2  8  8
2  3  1  3 

Możesz także użyć numpy.maximum.reduce. numpy.maximumjest ufunc (Universal Function) , a każdy ufunc mareduce :

df['C'] = np.maximum.reduce(df['A', 'B']].values, axis=1)
# df['C'] = np.maximum.reduce(df[['A', 'B']], axis=1)
# df['C'] = np.maximum.reduce(df, axis=1)
df

   A  B  C
0  1 -2  1
1  2  8  8
2  3  1  3

wprowadź opis obrazu tutaj

np.maximum.reducei np.maxwydają się być mniej więcej takie same (dla większości ramek DataFrame o normalnym rozmiarze) - i zdarzają się być odcień szybsze niż DataFrame.max. Wyobrażam sobie, że ta różnica z grubsza pozostaje stała i wynika z wewnętrznego narzutu (wyrównanie indeksowania, obsługa NaN itp.).

Wykres został wygenerowany za pomocą perfplot . Kod porównawczy, w celach informacyjnych:

import pandas as pd
import perfplot

np.random.seed(0)
df_ = pd.DataFrame(np.random.randn(5, 1000))

perfplot.show(
    setup=lambda n: pd.concat([df_] * n, ignore_index=True),
    kernels=[
        lambda df: df.assign(new=df.max(axis=1)),
        lambda df: df.assign(new=df.values.max(1)),
        lambda df: df.assign(new=np.nanmax(df.values, axis=1)),
        lambda df: df.assign(new=np.maximum.reduce(df.values, axis=1)),
    ],
    labels=['df.max', 'np.max', 'np.maximum.reduce', 'np.nanmax'],
    n_range=[2**k for k in range(0, 15)],
    xlabel='N (* len(df))',
    logx=True,
    logy=True)
cs95
źródło
Mała literówka: „df ['C'] = np.maximum.reduce (df ['A', 'B']]. Wartości, oś = 1)” powinno mieć wartość „df ['C'] = np.maximum. redukcja (df [['A', 'B']]. wartości, oś = 1) "
Velizar VESSELINOV