Як взяти фрагменти стовпців фрейму даних у пандах


264

Я завантажую деякі дані машинного навчання з файлу CSV. Перші 2 стовпці - це спостереження, а решта стовпці - функції.

В даний час я роблю наступне:

data = pandas.read_csv('mydata.csv')

що дає щось на зразок:

data = pandas.DataFrame(np.random.rand(10,5), columns = list('abcde'))

Я хотів би, щоб нарізати це dataframe в двох dataframes: один , що містять стовпці aі bі один , що містять стовпці c, dі e.

Неможливо написати щось подібне

observations = data[:'c']
features = data['c':]

Я не впевнений, який найкращий метод. Чи потрібно мені pd.Panel?

До речі, я вважаю, що індексація фрейму даних є досить непослідовною: data['a']це дозволено, але data[0]це не так. З іншого боку, data['a':]це не дозволено, але data[0:]є. Чи є для цього практична причина? Це дуже заплутано, якщо колонки індексуються Int, враховуючи цеdata[0] != data[0:1]


3
DataFrame за своєю суттю є об’єктом, що нагадує дік, коли ви робите df [...], проте деякі зручності, наприклад, df[5:10]були додані для вибору рядків ( pandas.pydata.org/pandas-docs/stable/… )
Уес Маккінні

1
То яка ця невідповідність є дизайнерським рішенням на користь зручності? Добре, але це, безумовно, має бути більш явним для початківців!
cpa

3
Розробка дизайну підтримки зручності робить криву навчання набагато крутішою. Мені б хотілося, щоб для початку була краща документація, яка лише представляла б послідовний інтерфейс. Наприклад, просто зосередитись на ix-інтерфейсі.
Ю. Шень

Відповіді:


243

Відповідь 2017 року - pandas 0.20: .ix застаріло. Використовуйте .loc

Дивіться застарілість у документах

.locвикористовує індексацію на основі міток для вибору і рядків, і стовпців. Мітки, що є значеннями індексу або стовпців. Нарізка з .locвключає останній елемент.

Давайте припустимо , що ми маємо в DataFrame з наступними стовпчиками:
foo, bar, quz, ant, cat, sat, dat.

# selects all rows and all columns beginning at 'foo' up to and including 'sat'
df.loc[:, 'foo':'sat']
# foo bar quz ant cat sat

.locприймає ті самі позначення фрагментів, що і списки Python для рядків і стовпців. Позначення фрагмента буттяstart:stop:step

# slice from 'foo' to 'cat' by every 2nd column
df.loc[:, 'foo':'cat':2]
# foo quz cat

# slice from the beginning to 'bar'
df.loc[:, :'bar']
# foo bar

# slice from 'quz' to the end by 3
df.loc[:, 'quz'::3]
# quz sat

# attempt from 'sat' to 'bar'
df.loc[:, 'sat':'bar']
# no columns returned

# slice from 'sat' to 'bar'
df.loc[:, 'sat':'bar':-1]
sat cat ant quz bar

# slice notation is syntatic sugar for the slice function
# slice from 'quz' to the end by 2 with slice function
df.loc[:, slice('quz',None, 2)]
# quz cat dat

# select specific columns with a list
# select columns foo, bar and dat
df.loc[:, ['foo','bar','dat']]
# foo bar dat

Ви можете нарізати рядки та стовпці. Наприклад, якщо у вас є 5 рядків з наклейками v, w, x, y,z

# slice from 'w' to 'y' and 'foo' to 'ant' by 3
df.loc['w':'y', 'foo':'ant':3]
#    foo ant
# w
# x
# y

якщо ваше використання застосовується з лямбда-рядом, як у: df['newcol'] = df.apply(lambda row: myfunc(row), axis=1) тоді ви можете в myfunc(row){... використовувати row['foo':'ant']. наприклад (відповідно до цієї відповіді StackOverflow ), всередині myfuncви можете евакуюватись, якщо будь-яке з них є нечисловим:row['foo':'ant'].apply(lambda x: isinstance(x, str)).any()
pashute

4
.ilocслід використовувати зараз, а не .loc. Виправте це, і я його схвалюю.
викрадено

1
@craned - це не правильно. З документації Pandas: .loc в основному базується на мітках, але може також використовуватися з булевим масивом. .loc підвищить KeyError, коли елементи не знайдені. Аналогічне твердження зроблено про .iloc excep, воно конкретно стосується нарізки на основі індексу. Іншими словами, у цьому прикладі він використовував індексацію на основі міток, а .loc - правильний вибір (в основному єдиний вибір). Якщо ви хочете нарізати, наприклад, позицію -row 5:10, тоді використовуйте .iloc
user2103050

149

Примітка: .ix застаріла з Pandas v0.20. Натомість слід використовувати .locабо .iloc, якщо потрібно.

Індекс DataFrame.ix - це те, до чого ви хочете отримати доступ. Це трохи заплутано (я погоджуюся, що індексація Pandas часом викликає здивування!), Але наступне, здається, робить те, що ви хочете:

>>> df = DataFrame(np.random.rand(4,5), columns = list('abcde'))
>>> df.ix[:,'b':]
      b         c         d         e
0  0.418762  0.042369  0.869203  0.972314
1  0.991058  0.510228  0.594784  0.534366
2  0.407472  0.259811  0.396664  0.894202
3  0.726168  0.139531  0.324932  0.906575

де .ix [фрагмент рядка, фрагмент стовпця] - те, що інтерпретується. Більше про індексацію Pandas тут: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-advanced


5
Будьте уважні, що діапазон панд включає обидві кінцеві точки, тобто>>>data.ix[:, 'a':'c'] a b c 0 0.859192 0.881433 0.843624 1 0.744979 0.427986 0.177159
коник

21
Кабіна декількох стовпців передається такdf.ix[:,[0,3,4]]
користувач602599

3
@Karmel: Схоже, помилка копіювання / вставки у вихідному тексті вище. Можливо, ви мали на увазі df.ix[:,'b':'e']?
ChaimG

6
Це краще використовувати locзамість ix: stackoverflow.com/a/31593712/4323
Джон Zwinck

5
Старі відповіді на зразок цієї потрібно видалити. .ix застаріла і ніколи не повинна використовуватися.
Тед Петру

75

Дозволяє використовувати титанічний набір даних із пакета Seaborn як приклад

# Load dataset (pip install seaborn)
>> import seaborn.apionly as sns
>> titanic = sns.load_dataset('titanic')

використовуючи назви стовпців

>> titanic.loc[:,['sex','age','fare']]

за допомогою індексів стовпців

>> titanic.iloc[:,[2,3,6]]

використання ix (старіша за Панди <.20 версія)

>> titanic.ix[:,[‘sex’,’age’,’fare’]]

або

>> titanic.ix[:,[2,3,6]]

використовуючи метод реіндекса

>> titanic.reindex(columns=['sex','age','fare'])

6
У пандах 0,20: .ixзастаріле.
Шихе Чжан

попередження Passing list-likes to .loc or [] with any missing label will raise KeyError in the future, you can use .reindex() as an alternative.про df.loc[:, some_list_of_columns]
депресію

35

Також, дано DataFrame

дані

як у вашому прикладі, якщо ви хочете витягнути лише стовпці a і d (наприклад, 1-й і 4-й стовпці), iloc mothod з фрейму даних панди - це те, що вам потрібно, і це могло б бути використане дуже ефективно. Все, що вам потрібно знати, - це індекс стовпців, які ви хочете витягнути. Наприклад:

>>> data.iloc[:,[0,3]]

дасть тобі

          a         d
0  0.883283  0.100975
1  0.614313  0.221731
2  0.438963  0.224361
3  0.466078  0.703347
4  0.955285  0.114033
5  0.268443  0.416996
6  0.613241  0.327548
7  0.370784  0.359159
8  0.692708  0.659410
9  0.806624  0.875476

25

Ви можете нарізати стовпці а DataFrame, посилаючись на назви кожного стовпця у списку, наприклад:

data = pandas.DataFrame(np.random.rand(10,5), columns = list('abcde'))
data_ab = data[list('ab')]
data_cde = data[list('cde')]

Отже, якщо я хочу, щоб усі дані починалися зі стовпця 'b', мені потрібно знайти індекс 'b' у data.column і зробити дані [data.columns [1:]]? Це канонічний спосіб діяти?
cpa

1
Ви маєте на увазі, що хочете вибрати всі стовпці від 'b' далі?
Брендан Вуд

Так, або вибір усіх стовпців у заданому діапазоні.
cpa

Я досить новачок у пандах, тому не можу говорити про те, що вважається канонічним. Я би зробив це так, як ви сказали, але використовуйте get_locфункцію on, data.columnsщоб визначити індекс стовпця 'b' чи будь-що інше.
Брендан Вуд

20

І якщо ви приїхали сюди, шукаючи нарізати два діапазони стовпців і поєднати їх разом (як я), ви можете зробити щось на кшталт

op = df[list(df.columns[0:899]) + list(df.columns[3593:])]
print op

Це створить новий фрейм даних з першими 900 стовпцями та (усіма) колонками> 3593 (за умови, що у вашому наборі даних є близько 4000 стовпців).


Чудово, хтось це випробував ... Мені було цікаво, це 0: 899, що отримує перші 900 колонок .. чому вони зробили це так? Це зовсім не так, як Python. При використанні діапазонів у python завжди є "до" не "до та не включається"
zwep

14

Ось як ви могли використовувати різні методи для вибіркового нарізання стовпців, включаючи селективне на основі міток, на основі індексу та селективного нарізання стовпців на основі діапазону.

In [37]: import pandas as pd    
In [38]: import numpy as np
In [43]: df = pd.DataFrame(np.random.rand(4,7), columns = list('abcdefg'))

In [44]: df
Out[44]: 
          a         b         c         d         e         f         g
0  0.409038  0.745497  0.890767  0.945890  0.014655  0.458070  0.786633
1  0.570642  0.181552  0.794599  0.036340  0.907011  0.655237  0.735268
2  0.568440  0.501638  0.186635  0.441445  0.703312  0.187447  0.604305
3  0.679125  0.642817  0.697628  0.391686  0.698381  0.936899  0.101806

In [45]: df.loc[:, ["a", "b", "c"]] ## label based selective column slicing 
Out[45]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

In [46]: df.loc[:, "a":"c"] ## label based column ranges slicing 
Out[46]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

In [47]: df.iloc[:, 0:3] ## index based column ranges slicing 
Out[47]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

### with 2 different column ranges, index based slicing: 
In [49]: df[df.columns[0:1].tolist() + df.columns[1:3].tolist()]
Out[49]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

Будь ласка, спробуйте уникати просто демпінгового коду як відповіді та спробуйте пояснити, що це робить і чому. Ваш код може бути не очевидним для людей, які не мають відповідного досвіду кодування. Будь ласка, відредагуйте свою відповідь, щоб включити роз’яснення, контекст і спробувати зазначити будь-які обмеження, припущення чи спрощення у своїй відповіді.
Sᴀᴍ Onᴇᴌᴀ


1

якщо кадр даних виглядає так:

group         name      count
fruit         apple     90
fruit         banana    150
fruit         orange    130
vegetable     broccoli  80
vegetable     kale      70
vegetable     lettuce   125

і вихід може бути таким

   group    name  count
0  fruit   apple     90
1  fruit  banana    150
2  fruit  orange    130

якщо ви використовуєте логічний оператор np.logical_not

df[np.logical_not(df['group'] == 'vegetable')]

більше про

https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.logic.html

інші логічні оператори

  1. logic_and (x1, x2, / [, out, where, ...]) Обчислити значення істинності елементів x1 AND x2.

  2. logic_or (x1, x2, / [, out, where, casting, ...]) Обчислити значення істинності елементів x1 АБО x2.

  3. logic_not (x, / [, out, where, casting, ...]) Обчислити значення істинності NOT x-element.
  4. logic_xor (x1, x2, / [, out, where, ..]) Обчислити значення істинності x1 XOR x2, що відповідає елементу.

0

Ще один спосіб отримати підмножину стовпців з вашої DataFrame, якщо припустити, що ви хочете виконати всі рядки:
data[['a','b']]і data[['c','d','e']]
якщо ви хочете використовувати числові індекси стовпців, ви можете зробити:
data[data.columns[:2]]іdata[data.columns[2:]]

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.