Jak dodać wiele kolumn do ramki danych pandy w jednym zadaniu?

122

Jestem nowy w pandach i próbuję wymyślić, jak jednocześnie dodać wiele kolumn do pand. Każda pomoc jest mile widziana. Idealnie chciałbym to zrobić w jednym kroku, a nie w wielu powtarzanych krokach ...

import pandas as pd

df = {'col_1': [0, 1, 2, 3],
        'col_2': [4, 5, 6, 7]}
df = pd.DataFrame(df)

df[[ 'column_new_1', 'column_new_2','column_new_3']] = [np.nan, 'dogs',3]  #thought this would work here...
biegające ptaki
źródło
Musisz podać, jaki masz błąd. Kiedy spróbuję tego na KeyError: "None of [Index(['column_new_1', 'column_new_2', 'column_new_3'], dtype='object')] are in the [columns]"
pandach

Odpowiedzi:

187

Spodziewałbym się, że twoja składnia też zadziała. Problem pojawia się, ponieważ podczas tworzenia nowych kolumn za pomocą składni listy kolumn ( df[[new1, new2]] = ...), pandy wymagają, aby prawa strona była ramką DataFrame (zwróć uwagę, że w rzeczywistości nie ma znaczenia, czy kolumny DataFrame mają takie same nazwy jak kolumny tworzysz).

Twoja składnia działa dobrze przy przypisywaniu wartości skalarnych do istniejących kolumn, a pandy z przyjemnością przypisują wartości skalarne do nowej kolumny za pomocą składni jednokolumnowej ( df[new1] = ...). Więc rozwiązaniem jest albo przekonwertowanie tego na kilka przypisań jednokolumnowych, albo utworzenie odpowiedniej ramki DataFrame dla prawej strony.

Oto kilka podejść, które będą działać:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'col_1': [0, 1, 2, 3],
    'col_2': [4, 5, 6, 7]
})

Następnie jedno z poniższych:

1) Trzy zadania w jednym przy użyciu rozpakowywania list:

df['column_new_1'], df['column_new_2'], df['column_new_3'] = [np.nan, 'dogs', 3]

2) DataFramewygodnie rozwija pojedynczy wiersz, aby dopasować go do indeksu, więc możesz to zrobić:

df[['column_new_1', 'column_new_2', 'column_new_3']] = pd.DataFrame([[np.nan, 'dogs', 3]], index=df.index)

3) Utwórz tymczasową ramkę danych z nowymi kolumnami, a następnie połącz ją z oryginalną ramką danych później:

df = pd.concat(
    [
        df,
        pd.DataFrame(
            [[np.nan, 'dogs', 3]], 
            index=df.index, 
            columns=['column_new_1', 'column_new_2', 'column_new_3']
        )
    ], axis=1
)

4) Podobnie jak poprzednio, ale użycie joinzamiast concat(może być mniej wydajne):

df = df.join(pd.DataFrame(
    [[np.nan, 'dogs', 3]], 
    index=df.index, 
    columns=['column_new_1', 'column_new_2', 'column_new_3']
))

5) Używanie dyktu jest bardziej "naturalnym" sposobem tworzenia nowej ramki danych niż dwie poprzednie, ale nowe kolumny będą sortowane alfabetycznie (przynajmniej przed Pythonem 3.6 lub 3.7 ):

df = df.join(pd.DataFrame(
    {
        'column_new_1': np.nan,
        'column_new_2': 'dogs',
        'column_new_3': 3
    }, index=df.index
))

6) Używaj .assign()z wieloma argumentami kolumnowymi.

Bardzo podoba mi się ten wariant odpowiedzi @ zero, ale podobnie jak poprzedni, nowe kolumny będą zawsze sortowane alfabetycznie, przynajmniej we wczesnych wersjach Pythona:

df = df.assign(column_new_1=np.nan, column_new_2='dogs', column_new_3=3)

7) To ciekawe (na podstawie https://stackoverflow.com/a/44951376/3830997 ), ale nie wiem, kiedy warto byłoby:

new_cols = ['column_new_1', 'column_new_2', 'column_new_3']
new_vals = [np.nan, 'dogs', 3]
df = df.reindex(columns=df.columns.tolist() + new_cols)   # add empty cols
df[new_cols] = new_vals  # multi-column assignment works for existing cols

8) Ostatecznie trudno pokonać trzy oddzielne zadania:

df['column_new_1'] = np.nan
df['column_new_2'] = 'dogs'
df['column_new_3'] = 3

Uwaga: wiele z tych opcji zostały już ujęte w innych odpowiedzi: Dodawanie wielu kolumn do DataFrame i ustawić je wynosić do istniejącej kolumny , Czy jest możliwe aby dodać kilka kolumn na raz do pand DataFrame? , Dodaj wiele pustych kolumn do pandy DataFrame

Matthias Fripp
źródło
Czy podejście # 7 ( .reindex) nie zmieniłoby indeksu ramki danych? Dlaczego ktoś miałby chcieć niepotrzebnie zmieniać indeks podczas dodawania kolumn, chyba że jest to wyraźny cel ...
Acumenus
1
.reindex()jest używany z columnsargumentem, więc zmienia tylko kolumnę „indeks” (nazwy). Nie zmienia indeksu wiersza.
Matthias Fripp
dla niektórych podejść możesz użyć OrderedDict: na przykładdf.join(pd.DataFrame( OrderedDict([('column_new_2', 'dogs'),('column_new_1', np.nan),('column_new_3', 3)]), index=df.index ))
hashmuke
@hashmuke To ma sens w przypadku wczesnych wersji Pythona. Może spodobać się zwłaszcza osobom używającym słowników do wielu rzeczy w Pandach, np. df = pd.DataFrame({'before': [1, 2, 3], 'after': [4, 5, 6]})Kontradf = pd.DataFrame(OrderedDict([('before', [1, 2, 3]), ('after', [4, 5, 6])])
Matthias Fripp
2
Jeśli używasz opcji z join, upewnij się, że nie masz duplikatów w swoim indeksie (lub użyj reset_indexpierwszego). Może zaoszczędzić kilka godzin na debugowaniu.
Guido
40

Możesz użyć assignz dyktowaniem nazw kolumn i wartości.

In [1069]: df.assign(**{'col_new_1': np.nan, 'col2_new_2': 'dogs', 'col3_new_3': 3})
Out[1069]:
   col_1  col_2 col2_new_2  col3_new_3  col_new_1
0      0      4       dogs           3        NaN
1      1      5       dogs           3        NaN
2      2      6       dogs           3        NaN
3      3      7       dogs           3        NaN
Zero
źródło
Czy istnieje sposób na zrobienie tego samego, który utrzymuje określoną kolejność kolumn?
user48956
1
Możesz zachować określoną kolejność we wcześniejszych wersjach Pythona, wywołując wielokrotnie assign: df.assign(**{'col_new_1': np.nan}).assign(**{'col2_new_2': 'dogs'}).assign(**{'col3_new_3': 3})
skasch
Jeśli nazwy kolumn zawierać tylko ciągi, które są nazwy zmiennych prawne: df.assign(col_new_1=np.nan, col2_new_2='dogs', col3_new_3=3). To utrzymuje porządek.
Tobias Bergkvist
9

Za pomocą concat :

In [128]: df
Out[128]: 
   col_1  col_2
0      0      4
1      1      5
2      2      6
3      3      7

In [129]: pd.concat([df, pd.DataFrame(columns = [ 'column_new_1', 'column_new_2','column_new_3'])])
Out[129]: 
   col_1  col_2 column_new_1 column_new_2 column_new_3
0    0.0    4.0          NaN          NaN          NaN
1    1.0    5.0          NaN          NaN          NaN
2    2.0    6.0          NaN          NaN          NaN
3    3.0    7.0          NaN          NaN          NaN

Nie jestem pewien, z czym chcesz zrobić [np.nan, 'dogs',3]. Może teraz ustawić je jako wartości domyślne?

In [142]: df1 = pd.concat([df, pd.DataFrame(columns = [ 'column_new_1', 'column_new_2','column_new_3'])])
In [143]: df1[[ 'column_new_1', 'column_new_2','column_new_3']] = [np.nan, 'dogs', 3]

In [144]: df1
Out[144]: 
   col_1  col_2  column_new_1 column_new_2  column_new_3
0    0.0    4.0           NaN         dogs             3
1    1.0    5.0           NaN         dogs             3
2    2.0    6.0           NaN         dogs             3
3    3.0    7.0           NaN         dogs             3
Nehal J Wani
źródło
jeśli był sposób na zrobienie drugiej części w jednym kroku - tak, jako przykład, wartości stałych w kolumnach.
Runningbirds
3

użycie rozumienia list pd.DataFrameipd.concat

pd.concat(
    [
        df,
        pd.DataFrame(
            [[np.nan, 'dogs', 3] for _ in range(df.shape[0])],
            df.index, ['column_new_1', 'column_new_2','column_new_3']
        )
    ], axis=1)

wprowadź opis obrazu tutaj

piRSquared
źródło
3

jeśli dodajesz wiele brakujących kolumn (a, b, c, ....) o tej samej wartości, tutaj 0, zrobiłem to:

    new_cols = ["a", "b", "c" ] 
    df[new_cols] = pd.DataFrame([[0] * len(new_cols)], index=df.index)

Opiera się na drugim wariancie zaakceptowanej odpowiedzi.

A. Rabus
źródło
0

Chcę tylko zwrócić uwagę na tę opcję 2 w odpowiedzi @Matthias Fripp

(2) Nie spodziewałbym się, że DataFrame będzie działać w ten sposób, ale tak jest

df [['column_new_1', 'column_new_2', 'column_new_3']] = pd.DataFrame ([[np.nan, 'psy', 3]], index = df.index)

jest już udokumentowane w dokumentacji własnej pand http://pandas.pydata.org/pandas-docs/stable/indexing.html#basics

Możesz przekazać listę kolumn do [], aby wybrać kolumny w tej kolejności. Jeśli kolumna nie jest zawarta w DataFrame, zostanie zgłoszony wyjątek. W ten sposób można również ustawić wiele kolumn. Może się to okazać przydatne do zastosowania przekształcenia ( w miejscu ) do podzbioru kolumn.

halfmoonhalf
źródło
Myślę, że jest to dość standardowe w przypadku przypisywania wielu kolumn. Zaskoczyło mnie to, że pd.DataFrame([[np.nan, 'dogs', 3]], index=df.index)replikuje jeden podany wiersz, aby utworzyć całą ramkę danych o tej samej długości co indeks.
Matthias Fripp
0

Jeśli chcesz tylko dodać puste nowe kolumny, reindeks wykona zadanie

df
   col_1  col_2
0      0      4
1      1      5
2      2      6
3      3      7

df.reindex(list(df)+['column_new_1', 'column_new_2','column_new_3'], axis=1)
   col_1  col_2  column_new_1  column_new_2  column_new_3
0      0      4           NaN           NaN           NaN
1      1      5           NaN           NaN           NaN
2      2      6           NaN           NaN           NaN
3      3      7           NaN           NaN           NaN

przykład pełnego kodu

import numpy as np
import pandas as pd

df = {'col_1': [0, 1, 2, 3],
        'col_2': [4, 5, 6, 7]}
df = pd.DataFrame(df)
print('df',df, sep='\n')
print()
df=df.reindex(list(df)+['column_new_1', 'column_new_2','column_new_3'], axis=1)
print('''df.reindex(list(df)+['column_new_1', 'column_new_2','column_new_3'], axis=1)''',df, sep='\n')

w przeciwnym razie odpowiedz na zera z przypisaniem

Markus Dutschke
źródło
0

Nie czuję się komfortowo, używając „indeksu” i tak dalej ... może pojawić się jak poniżej

df.columns
Index(['A123', 'B123'], dtype='object')

df=pd.concat([df,pd.DataFrame(columns=list('CDE'))])

df.rename(columns={
    'C':'C123',
    'D':'D123',
    'E':'E123'
},inplace=True)


df.columns
Index(['A123', 'B123', 'C123', 'D123', 'E123'], dtype='object')
Alex
źródło