Как отбрасывать строки в пандах, совмещая столбцы и выполняя уравнение в другом столбце? - PullRequest
1 голос
/ 19 июня 2019

Я имею дело с некоторыми финансовыми данными, содержащими развороты. Сторнирование - это, по сути, исправление в таблице, которое смещает другие значения в таблице, добавляя в таблицу равное количество противоположного знака. Моя работа - очистить эти ценности. Возьмите для примера этот кадр данных:

df = pd.DataFrame({"a":["a","b","c","a","a"],
                  "b":[-2,5,2,2,7],
                 "xtra_col":["X","X","X","X","X"]})

    a   b   xtra_col
0   a   -2  X
1   b   5   X
2   c   2   X
3   a   2   X
4   a   7   X

В этом случае строка 3 является обращением к строке 0, и они должны быть отброшены. В то же время строка 2 не является обращением к строке 0, но противоположными значениями, поскольку они не совпадают в столбце a. Результат должен выглядеть так.

    a   b   xtra_col
0   b   5   X
1   c   2   X
2   a   7   X

Вопрос в том, как я могу удалить такие развороты из моей таблицы? Я смотрел на drop_duplicates() с подмножеством a и b, но это не сработало бы, потому что оно будет соответствовать только тем же значениям, но не противоположным. У меня такое чувство, что я могу достичь чего-то с groupby, но я не уверен, как это организовать.

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

df = pd.DataFrame({"a":["a","b","c","a","a"],
                  "b":[-2,5,2,2.0,-2],
                 "xtra_col":["X","X","X","X","X"]})


a   b   xtra_col
0   a   -2.0    X
1   b   5.0 X
2   c   2.0 X
3   a   2.0 X
4   a   -2.0    X

вывод должен быть:

a   b   xtra_col
1   b   5.0 X
2   c   2.0 X
3   1   -2.0    X

Ответы [ 3 ]

3 голосов
/ 19 июня 2019

Если возможен только один числовой столбец b, создайте отфильтрованный DataFrame, инвертируйте b по нескольким -1 и сопоставляйте строки по DataFrame.merge, последний отфильтруйте значения индекса по Series.isin и boolean indexing:

df1 = df[df['b'].lt(0)].copy()
df1['b'] *= -1

df2 = df1.reset_index().merge(df.reset_index(), on=['a','b']).filter(like='index_')
print (df2)
   index_x  index_y
0        0        3

df = df[~df.index.isin(df2.values.ravel())]
print (df)
   a  b xtra_col
1  b  5        X
2  c  2        X
4  a  7        X

Если возможно, еще одна строка a 2, и вам нужно избегать ее удаления (поскольку она не связана с другой a -2), добавьте GroupBy.cumcount для столбца счетчика в отфильтрованном и оригинальном DataFrame:

df = pd.DataFrame({"a":["a","b","c","a","a",'a'],
                  "b":[-2,5,2,2,7,2],
                 "xtra_col":["X","X","X","X","X",'X']})


df1 = df[df['b'].lt(0)].copy()
c = df1.select_dtypes(np.number).columns
df1[c] *= -1

df1['g'] = df1.groupby(['a','b']).cumcount()
df['g'] = df.groupby(['a','b']).cumcount()
df2 = df1.reset_index().merge(df.reset_index(), on=['a','b','g']).filter(like='index_')
print (df2)


df = df[~df.index.isin(df2.values.ravel())]
print (df)
   a  b xtra_col  g
1  b  5        X  0
2  c  2        X  0
4  a  7        X  0
5  a  2        X  1
1 голос
/ 19 июня 2019

Использование возможностей SQL в Python. Здесь вы присоединяете таблицу (dataframe) к себе, проверяя случаи, когда столбец a совпадает, а столбец b переворачивается. Используя предложение where, вы можете фильтровать.

см. Макет ниже:

import sqlite3
import pandas as pd
import numpy as np
df = pd.DataFrame({"a":["a","b","c","a","a"],
                  "b":[-2,5,2,2,7],
                 "xtra_col":["X","X","X","X","X"]})

#Make the db in memory
conn = sqlite3.connect(':memory:')
df.to_sql('tab', conn, index=False)

qry = '''
    select  
       tab1.a,tab1.b,tab1.xtra_col
    from
        tab as tab1 

        left join tab as tab2 on
            tab1.a =tab2.a
            and
            tab1.b = -tab2.b
        where tab2.a is null
    '''
dfres = pd.read_sql_query(qry, conn)
dfres

и результаты здесь:

a   b   xtra_col
0   b   5   X
1   c   2   X
2   a   7   X
0 голосов
/ 19 июня 2019

Вот еще один способ сделать с apply поиск недействительных строк и удалить их:

# Import module
import pandas as pd

# Your data
df = pd.DataFrame({"a": ["a", "b", "c", "a", "a"],
                   "b": [-2, 5, 2, 2, 7],
                   "xtra_col": ["X", "X", "X", "X", "X"]})

# Filtering function
def filter_row(row):
    # Your condition comparing the current row with the whole dataframe
    if sum((df.a == row.a) & (df.b == -row.b)) == 1:
        return row

# Apply the filter method
row_to_remove = df.apply(filter_row, axis=1)
print(row_to_remove)  # You can use drop NA to remove NA rows
#       a    b xtra_col
# 0     a - 2.0       X
# 1  None  NaN     None
# 2  None  NaN     None
# 3     a  2.0        X
# 4  None  NaN     None

# Drop invalid rows
result = df[(df != row_to_remove).any(axis=1)]
print(result)
#    a  b xtra_col
# 1  b  5        X
# 2  c  2        X
# 4  a  7        X
...