Фильтр по нескольким столбцам во фрейме данных Pandas с помощью цикла - PullRequest
0 голосов
/ 11 февраля 2019

Контекст: У меня есть данные в excel, которые мы обрабатываем через Pandas для очистки, а затем в дальнейшем используем их в модели ML.В процессе очистки я пытаюсь отфильтровать данные на основе нескольких столбцов как условие ИЛИ.Этот набор столбцов имеет имя заголовка в качестве даты начала недели, поэтому эти 7 столбцов будут представлять 7 недель.Название заголовка этого столбца меняется каждую неделю.Следовательно, я не могу сохранить непротиворечивый код для автоматического выбора имени заголовка.

Логика, которую я попробовал: Я написал фрагмент кода для печати условия «ИЛИ», используястолбцы с этой датой, после чего я копирую и вставляю этот оператор печати в часть кадров данных.Ниже показано, как это выглядит:

Я копирую вставку столбца на данный момент.Но я предполагаю, что смогу построить логику для идентификации столбца даты, применив условие на основе типа к именам столбцов

Пример данных:

 1/20/2019 1/27/2019  2/3/2019 2/10/2019    2/17/2019 2/24/2019  3/3/2019  \
0   0(80CS,8H)   0(80CS)   0(80CS)   0(80CS)      0(80CS)   0(80CS)   0(80CS)   
1   0(50CS,8H)   0(50CS)   0(50CS)   0(50CS)      0(50CS)   0(50CS)   0(50CS)   
2   0(40CS,8H)   0(40CS)   0(40CS)   0(40CS)      0(40CS)   0(40CS)   0(40CS)   
3   0(40CS,8H)   0(40CS)   0(40CS)   0(40CS)      0(40CS)   0(40CS)   0(40CS)   
4   0(40CS,8H)   0(40CS)   0(40CS)   0(40CS)      0(40CS)   0(40CS)   0(40CS)   
5   0(40CS,8H)   0(40CS)   0(40CS)   0(40CS)      0(40CS)   0(40CS)   0(40CS)   
6  12(25CS,8H)  15(25CS)  15(25CS)  15(25CS)     15(25CS)  15(25CS)  15(25CS)   
7  11(28CS,8H)  12(28CS)  12(28CS)  12(28CS)     12(28CS)  12(28CS)  12(28CS)   
8   8(30CS,8H)  10(30CS)  10(30CS)  10(30CS)  2(30CS,32T)  10(30CS)  10(30CS)   
9   0(40CS,8H)   0(40CS)   0(40CS)   0(40CS)      0(40CS)   0(40CS)   0(40CS)   

  3/10/2019 3/17/2019 3/24/2019 3/31/2019  4/7/2019  
0   0(80CS)   0(80CS)   0(80CS)   0(80CS)   0(80CS)  
1   0(50CS)   0(50CS)   0(50CS)   0(50CS)   0(50CS)  
2   0(40CS)   0(40CS)   0(40CS)   0(40CS)   0(40CS)  
3   0(40CS)   0(40CS)   0(40CS)   0(40CS)   0(40CS)  
4   0(40CS)   0(40CS)   0(40CS)   0(40CS)   0(40CS)  
5   0(40CS)   0(40CS)   0(40CS)   0(40CS)   0(40CS)  
6  15(25CS)  15(25CS)  15(25CS)  20(20CS)  20(20CS)  
7  12(28CS)  12(28CS)  12(28CS)  12(28CS)  12(28CS)  
8  10(30CS)  10(30CS)  10(30CS)  10(30CS)  10(30CS)  
9   0(40CS)   0(40CS)   0(40CS)   0(40CS)   0(40CS)


avail_col = ['1/20/2019',
   '1/27/2019', '2/3/2019', '2/10/2019', '2/17/2019', '2/24/2019',
   '3/3/2019', '3/10/2019', '3/17/2019', '3/24/2019', '3/31/2019',
   '4/7/2019']

##changing the data type of selected columns
for i in avail_col:
    avail_dat[i] = avail_dat[i].astype(str).apply(lambda x: x.split('(')[0])
    avail_dat[i] = avail_dat[i].str.replace('-','0')
    avail_dat[i] = avail_dat[i].astype(float)


or_str = ''
for i in avail_col:
    or_str = "(avail_dat['"+i+"'] >= 24) | "
    print(or_str)

Видимо, я могуне передать переменную во фрейм данных для фильтрации, или я пока не знаю, как это сделать, поэтому я скопирую вставленный напечатанный оператор в приведенный ниже код, чтобы отфильтровать фрейм данных

 avail_dat = avail_dat[(avail_dat['1/20/2019'] >= 24) | 
(avail_dat['1/27/2019'] >= 24) | 
(avail_dat['2/3/2019'] >= 24) | 
(avail_dat['2/10/2019'] >= 24) | 
(avail_dat['2/17/2019'] >= 24) | 
(avail_dat['2/24/2019'] >= 24) | 
(avail_dat['3/3/2019'] >= 24) | 
(avail_dat['3/10/2019'] >= 24) | 
(avail_dat['3/17/2019'] >= 24) | 
(avail_dat['3/24/2019'] >= 24) | 
(avail_dat['3/31/2019'] >= 24) | 
(avail_dat['4/7/2019'] >= 24)
 ]

Есть лиспособ передать переменную вместо копирования каждый раз?

Ответы [ 3 ]

0 голосов
/ 11 февраля 2019

Вау.Здесь есть над чем подумать.

Во-первых, я думаю, что вы можете сделать намного лучше с выбором столбцов.Например, вы можете сделать следующее, чтобы сгенерировать список нужных вам столбцов (поскольку вы сказали, что они с шагом 7 дней):

columns_you_want = list(pd.date_range(start='1/20/2019',freq=pd.DateOffset(days=7),end='4/7/2019').strftime('%m/%d/%Y'))

Затем вы можете просто сделать:

df_avail = df.filter(columns_you_want)

Наконец, что-то вроде:

df_avail[df_avail>24].dropna(how='any',axis=0)

Кажется, что вы хотите, хотя я не уверен насчет последнего шага, так как вы не предоставили желаемого результата.

0 голосов
/ 11 февраля 2019

Если я правильно понял, вы сравниваете число перед скобками и игнорируете знак минус.Если это так, вы можете попытаться транспонировать фрейм данных и затем применить функцию извлечения, или вы можете использовать функцию разбиения, подобную той, которую вы написали, что может работать лучше, если у вас действительно есть десятичные дроби:

dft = df.transpose()
for col in dft.columns:
    dft[col] = dft[col].str.extract(r'-?([0-9]+)\(.*').astype(float)
mask = dft >= 24
0 голосов
/ 11 февраля 2019

Вы можете сделать это, выполнив каждый из ваших фильтров отдельно, а затем объединить их позже.Вот так:

import numpy as np

# add all your boolean series to a list
all_masks = []
for col in avail_col:
    condition = (avail_dat[col] >= 24)
    all_masks.append(condition)

# use numpy to select the rows where any record evaluates to True
mask = np.array(all_masks).any(axis=0)
avail_dat.loc[mask]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...