我正在处理一些包含冲销的财务数据。反转基本上是表中的一种校正,它通过在表中添加等量的相反符号来抵消表中的另一个值。我的工作是清除这些价值观。 以这个数据框为例:
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
答案 0 :(得分:3)
如果仅可能有一个数字列None
,则创建过滤后的DataFrame,将b
反转多个b
,并按DataFrame.merge
匹配行,最后按{{ 3}}和Series.isin
:
-1
如果可能的话,另外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
中为计数器列添加boolean indexing
:< / p>
DataFrame
答案 1 :(得分:1)
在python中使用SQL的功能。在这里,您将表(数据框)连接到其自身,同时检查列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
答案 2 :(得分:0)
这是使用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