Как взять столбцы-фрагменты данных в пандах


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 - панды 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, за исключением того, что оно конкретно относится к разрезанию на основе индекса. Другими словами, в этом примере он использовал индексирование на основе меток, и .loc - правильный выбор (в основном единственный выбор). Например, если вы хотите нарезать по позициям -rows 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 [срез строки, срез столбца] - это то, что интерпретируется. Подробнее об индексации панд здесь: 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]]
user602599

3
@Karmel: В приведенном выше выводе выглядит ошибка копирования / вставки. Возможно, вы имели в виду df.ix[:,'b':'e']?
ChaimG

6
Лучше использовать locвместо ix: stackoverflow.com/a/31593712/4323
Джон Цвинк

5
Старые ответы, подобные этому, необходимо удалить. .ix устарела и никогда не должна использоваться.
Тед Петру

75

Давайте использовать в качестве примера титановый набор данных из пакета морского происхождения

# 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 (старше Pandas <.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]
Marc Maxmeister

35

Кроме того, учитывая DataFrame

данные

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

>>> 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

Вы можете нарезать вдоль столбцов a 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.columns и выполнить data [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 И x2 поэлементно.

  2. logic_or (x1, x2, / [, out, where, casting, ...]) Вычисляет значение истинности x1 ИЛИ x2 поэлементно.

  3. logic_not (x, / [, out, where, casting, ...]) Вычисляет значение истинности NOT x поэлементно.
  4. логический_xor (x1, x2, / [, out, где, ..]) Вычисляет значение истинности 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.