Удалить строки данных на основе двух зависимых условий - PullRequest
1 голос
/ 10 ноября 2019

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

Для каждой строки: Условие № 1: проверьте два столбца на значение ноль (0). Если это правда, сохраняйте строку и переходите к следующему. Если какой-либо из столбцов имеет значение ноль (0), условие имеет значение True.

Если условие № 1 равно False (нет нулей ни в столбце 1, ни в 4) Проверьте все оставшиеся столбцы в строке. Если какой-либо из оставшихся столбцов имеет значение ноль, удалите строку.

Я бы хотел, чтобы отфильтрованный фрейм данных был возвращен как новый отдельный фрейм данных.

Пока мой код:

# https://codereview.stackexchange.com/questions/185389/dropping-rows-from-a-pandas-dataframe-where-some-of-the-columns-have-value-0/185390
# https://thispointer.com/python-pandas-how-to-drop-rows-in-dataframe-by-conditions-on-column-values/
# https://stackoverflow.com/questions/29763620/how-to-select-all-columns-except-one-column-in-pandas

import pandas as pd

df = pd.DataFrame({'Col1': [7, 6, 0, 1, 8],
                   'Col2': [0.5, 0.5, 0, 0, 7],
                   'Col3': [0, 0, 3, 3, 6],
                   'Col4': [7, 0, 6, 4, 5]})

print(df)
print()

exclude = ['Col1', 'Col4']
all_but_1_and_4 = df[df.columns.difference(exclude)]        # Filter out columns 1 and 4
print(all_but_1_and_4)
print()


def delete_rows(row):
    if row['Col1'] == 0 or row['Col4'] == 0:    # Is the value in either Col1 or Col4 zero(0)
        skip = True                             # If it is, keep the row
        if not skip:                            # If not, check the second condition
            is_zero = all_but_1_and_4.apply(lambda x: 0 in x.values, axis=1).any()      # Are any values in the remaining columns zero(0)
            if is_zero:                         # If any of the remaining columns has a value of zero(0)
                pass
                # drop the row being analyzed   # Drop the row.


new_df = df.apply(delete_rows, axis=1)
print(new_df)

Я не знаю, как на самом деле отбросить строку, если выполнены оба моих условия.

В моем игрушечном фрейме данных строки 1, 2 и 4 должны быть сохранены, 0 и 3 удалены.

Я не хочу вручную проверять все столбцы для шага 2, потому что их несколько сотен. Вот почему я отфильтровал с помощью .difference ().

Ответы [ 2 ]

1 голос
/ 10 ноября 2019

Ответ WeNYoBen превосходен, поэтому я покажу только ошибки в вашем коде:

  1. Условие в следующем выражении if никогда не будет выполнено:

        skip = True                             # If it is, keep the row
        if not skip:                            # If not, check the second condition
    

    Вы, вероятно, хотели бы удалить отступ следующих строк, то есть что-то вроде

        skip = True                             # If it is, keep the row
    if not skip:                            # If not, check the second condition
    

    , что аналогично простому else:, без необходимости skip = True:

    else:                            # If not, check the second condition
    
  2. Условие в следующем операторе if всегда будет выполняться, если хотя бы одно значение в вашей таблице целом равно нулю (поэтому не только втекущая строка, как вы и предполагали):

        is_zero = all_but_1_and_4.apply(lambda x: 0 in x.values, axis=1).any()      # Are any values in the remaining columns zero(0)
        if is_zero:                         # If any of the remaining columns has a value of zero(0)
    

    , поскольку all_but_1_and_4.apply(lambda x: 0 in x.values, axis=1) - это серия из True / False значений - по одному на каждую строку в таблице all_but_1_and_4,Поэтому после применения к нему метода .any() вы получите то, что я сказал.


Примечание:

Ваш подход неплох, вы можете добавить переменнуюdropThisRow в вашей функции, установите его на True или False в зависимости от условий и верните его.
Затем вы можете использовать свою функцию для создания серии True / False и использовать ее для созданияВаша целевая таблица:

dropRows = df.apply(delete_rows, axis=1)   # True/False for dropping/keeping - for every row
new_df = df[~dropRows]                     # Select only rows with False
1 голос
/ 10 ноября 2019

Что я буду делать

s1=df[exclude].eq(0).any(1)
s2=df[df.columns.difference(exclude)].eq(0).any(1)

~(~s1&s2) #s1 | ~s2
Out[97]: 
0    False
1     True
2     True
3    False
4     True
dtype: bool
yourdf=df[s1 | ~s2].copy()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...