Python 如何使用pandas进行逐单元比较?

Python 如何使用pandas进行逐单元比较?,python,pandas,Python,Pandas,假设我有一个df,如下所示 col1 | type | date_1 | date_2 | date_3 |.... | date_n ab | A | -10 | | -10 ab | B | 100 | 99 | -12 cd | A | 0 | -25 | 6 cd | B | -1 | 8 | -34 ab | A

假设我有一个df,如下所示

col1   | type   | date_1 | date_2 | date_3 |.... | date_n
ab     |   A    |  -10   |        |  -10
ab     |   B    |  100   |   99   |  -12
cd     |   A    |   0    |  -25   |   6
cd     |   B    |  -1    |   8    |  -34
ab     |   A    |   98   |  -9    |   0
ab     |   B    |  -7    |  -2    |   0
第一步是删除所有正数,包括0

现在,df应该是这样的

col1   | type   | date_1 | date_2 | date_3 | .... | date_n
ab     |   A    |  -10   |        |  -10   |
ab     |   B    |        |        |  -12   |
cd     |   A    |        |  -25   |        |
cd     |   B    |  -1    |        |  -34   |
ab     |   A    |        |  -9    |        |
ab     |   B    |  -7    |  -2    |        |
第二步是根据“类型”A和B比较每个“日期”列的数字

  • 如果“类型”A行为负数,而“类型”B为空,则删除“类型”A的“日期”列的负数

  • 如果“type”B行为负数,而“type”a为空,则不执行任何操作

  • 如果两种类型都为空,则不执行任何操作

在此步骤之后,df应该如下所示

col1   | type   | date_1 | date_2 | date_3 | .... | date_n
ab     |   A    |        |        |  -10   |
ab     |   B    |        |        |  -12   |
cd     |   A    |        |        |        |
cd     |   B    |  -1    |        |  -34   |
ab     |   A    |        |  -9    |        |
ab     |   B    |  -7    |  -2    |        |
col1   | type   | date_1 | date_2 | date_3 | .... | date_n
ab     |   A    |        |        |        |
ab     |   B    |        |        |  -12   |
cd     |   A    |        |        |        |
cd     |   B    |  -1    |        |  -34   |
ab     |   A    |        |  -9    |        |
ab     |   B    |  -7    |        |        |
最后一步,

  • 如果两种类型的电流均为负值,则对于每组col1(ab、cd、ab),检查同一行相同Ath和Bth的左侧值

    1) If both types A and B values are blank, then remove the remove the negative number of current row 'type' A and keep the -ve number of 'type' B
    
    2) If either of the types are blank, then remove the negative of the current row 'type' B and keep the -ve number of 'type' A
    
最后,最终的_df应该如下所示

col1   | type   | date_1 | date_2 | date_3 | .... | date_n
ab     |   A    |        |        |  -10   |
ab     |   B    |        |        |  -12   |
cd     |   A    |        |        |        |
cd     |   B    |  -1    |        |  -34   |
ab     |   A    |        |  -9    |        |
ab     |   B    |  -7    |  -2    |        |
col1   | type   | date_1 | date_2 | date_3 | .... | date_n
ab     |   A    |        |        |        |
ab     |   B    |        |        |  -12   |
cd     |   A    |        |        |        |
cd     |   B    |  -1    |        |  -34   |
ab     |   A    |        |  -9    |        |
ab     |   B    |  -7    |        |        |
对于最后一步,比较应从“日期2”开始

解决这个问题的最好办法是什么?任何帮助都将不胜感激

注意:我不能使用列标题(日期标题)来操作数据,因为它们会不断变化

测试数据:

{'column1': ['CT', 'CT', 'NBB', 'NBB', 'CT', 'CT', 'NBB', 'NBB', 'HHH', 'HHH', 'TP1', 'TP1', 'TPR', 'TPR', 'PP1', 'PP1', 'PP1', 'PP1'], 'column2': ['POUPOU', 'POUPOU', 'PRPRP', 'PRPRP', 'STDD', 'STDD', 'STDD', 'STDD', 'STEVT', 'STEVT', 'SYSYS', 'SYSYS', 'SYSYS', 'SYSYS', 'SHW', 'SHW', 'JV', 'JV'], 'column3': ['V', 'CV', 'V', 'CV', 'V', 'CV', 'V', 'CV', 'V', 'CV', 'V', 'CV', 'V', 'CV', 'V', 'CV', 'V', 'CV'], 'column4': ['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B'], 'column5': [nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan], 'column6': ['BBB', 'BBB', 'CCC', 'CCC', 'BBB', 'BBB', 'BBB', 'BBB', 'VVV', 'VVV', 'CHCH', 'CHCH', 'CHCH', 'CHCH', 'CCC', 'CCC', 'CHCH', 'CHCH'], 'column7': ['Apr-21', 'Apr-21', 'Apr-21', 'Apr-21', 'Apr-21', 'Apr-21', 'Apr-21', 'Apr-21', 'Mar-21', 'Mar-21', 'Mar-21', 'Mar-21', 'Mar-21', 'Mar-21', 'Apr-21', 'Apr-21', 'Mar-21', 'Mar-21'], 'Feb-21': [11655, 0, 0, 0, 121117, 0, 14948, 0, 0, 0, 0, 0, 0, 0, 1838, 0, 0, 0], 'Mar-21': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -16474.0, -16474.0, 7000.0, 7000.0, -19946.0, -19946.0, 16084.44444444444, 0.0, 0.0, 0.0], 'Apr-21': [104815.0, 104815.0, 17949.0, 17949.0, 96132.0, 96132.0, 0.0, 0.0, -17001.0, -33475.0, -878.0, 6122.0, 8398.0, -11548.0, -5297.073170731703, -5297.073170731703, -282.0, -282.0], 'May-21': [78260.0, 183075.0, 42557.0, 60506.0, -15265.0, 80867.0, -18.0, -18.0, 21084.0, -12391.0, -1831.0, 4291.0, 2862.0, -8686.0, 5261.25, -35.8231707317027, -369.0, -651.0], 'Jun-21': [-52480.0, 130595.0, -13258.0, 47248.0, -35577.0, 45290.0, 2434.0, 2416.0, 31147.0, 18756.0, -4310.0, -19.0, -4750.0, -13436.0, -92.0, -127.8231707317027, -280.0, -931.0], 'Jul-21': [-174544.0, -43949.0, -38127.0, 9121.0, -124986.0, -79696.0, -9707.0, -7291.0, 13577.0, 32333.0, 0.0, -19.0, -15746.0, -29182.0, 93.0, -34.8231707317027, -319.0, -1250.0], 'Aug-21': [35498.0, -8451.0, -37094.0, -27973.0, 79021.0, -675.0, -1423.0, -8714.0, 32168.0, 64501.0, 0.0, -19.0, 18702.0, -10480.0, 4347.634146341465, 4312.810975609762, -341.0, -1591.0], 'Sep-21': [44195.0, 35744.0, 2039.0, -25934.0, 70959.0, 70284.0, 2816.0, -5898.0, 38359.0, 102860.0, 0.0, -19.0, 18119.0, 7639.0, 5302.222222222219, 9615.033197831981, 0.0, -1591.0], 'Oct-21': [-13163.0, 22581.0, -4773.0, -30707.0, 205080.0, 275364.0, -709.0, -6607.0, -1397.0, 101463.0, 0.0, -19.0, 0.0, 7639.0, -34.0, 9581.033197831981, 0.0, -1591.0]}
预期产出:

{'column1': ['CT', 'CT', 'NBB', 'NBB', 'CT', 'CT', 'NBB', 'NBB', 'HHH', 'HHH', 'TP1', 'TP1', 'TPR', 'TPR', 'PP1', 'PP1', 'PP1', 'PP1'], 'column2': ['POUPOU', 'POUPOU', 'PRPRP', 'PRPRP', 'STDD', 'STDD', 'STDD', 'STDD', 'STEVT', 'STEVT', 'SYSYS', 'SYSYS', 'SYSYS', 'SYSYS', 'SHW', 'SHW', 'JV', 'JV'], 'column3': ['V', 'CV', 'V', 'CV', 'V', 'CV', 'V', 'CV', 'V', 'CV', 'V', 'CV', 'V', 'CV', 'V', 'CV', 'V', 'CV'], 'column4': ['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B'], 'column5': [nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan], 'column6': ['BBB', 'BBB', 'CCC', 'CCC', 'BBB', 'BBB', 'BBB', 'BBB', 'VVV', 'VVV', 'CHCH', 'CHCH', 'CHCH', 'CHCH', 'CCC', 'CCC', 'CHCH', 'CHCH'], 'column7': ['Apr-21', 'Apr-21', 'Apr-21', 'Apr-21', 'Apr-21', 'Apr-21', 'Apr-21', 'Apr-21', 'Mar-21', 'Mar-21', 'Mar-21', 'Mar-21', 'Mar-21', 'Mar-21', 'Apr-21', 'Apr-21', 'Mar-21', 'Mar-21'], 'Feb-21': [nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan], 'Mar-21': [nan, nan, nan, nan, nan, nan, nan, nan, nan, -16474.0, nan, nan, nan, -19946.0, nan, nan, nan, nan], 'Apr-21': [nan, nan, nan, nan, nan, nan, nan, nan, -17001.0, nan, nan, nan, nan, -11548.0, nan, -5297.073170731703, nan, -282.0], 'May-21': [nan, nan, nan, nan, nan, nan, nan, -18.0, nan, -12391.0, nan, nan, nan, -8686.0, nan, -35.8231707317027, -369.0, nan], 'Jun-21': [nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, -19.0, -4750.0, nan, -92.0, nan, -280.0, nan], 'Jul-21': [nan, -43949.0, nan, nan, nan, -79696.0, nan, -7291.0, nan, nan, nan, -19.0, -15746.0, nan, nan, -34.8231707317027, -319.0, nan], 'Aug-21': [nan, -8451.0, nan, -27973.0, nan, -675.0, -1423.0, nan, nan, nan, nan, -19.0, nan, -10480.0, nan, nan, -341.0, nan], 'Sep-21': [nan, nan, nan, -25934.0, nan, nan, nan, -5898.0, nan, nan, nan, -19.0, nan, nan, nan, nan, nan, -1591.0], 'Oct-21': [nan, nan, -4773.0, nan, nan, nan, -709.0, nan, nan, nan, nan, -19.0, nan, nan, nan, nan, nan, -1591.0]}


使用
numpy
和构建真值表的替代方法。步骤3的逻辑是位写一次,从不读。添加了另一个测试用例

输出 空白和负片A
  • 用更复杂的二进制逻辑替换步骤1

到目前为止你试过什么了吗?可以解释更多的最后一步吗?为什么要删除
ef
-2
ab
-10
?什么意思
检查同一行的左侧
?最后一步,我们从列date_2开始,将值与日期_1的值进行比较。对于ef,我们删除了-2,因为在左侧,即列date_1中的值为负值,并且根据所述条件,删除了相应类型B的值,并保留了类型A。希望这有帮助!根据最后一步的第二点,这是正确的。@royalewithcheese-答案已编辑。@royalewithcheese-请给我一些时间,我更改答案以确保正确working@royalewithcheese-处理数据不容易,但我可以试试。对于您的解决方案-col1,type@royalewithcheese-只是考虑不合并备选方案,正在努力。顺便说一句,有很多列没有
type、col1
和datetimes列?我已经对第3步做了详细的解释,你可以看一下,如果有什么不清楚的地方请告诉我。此外,我还对问题进行了编辑。更新-第3步的逻辑有效,但可读性不强…如果第2步,我想保留B的负数,如果B有负数,但a是空的,我需要更改什么?我已经更新了答案-这是对第1步更新的修改。当我使用测试数据(我在问题中添加了测试数据)运行代码时,我在最后一步得到以下错误
操作数无法与形状(12,8)(12,2)
import io
import pandas as pd
import numpy as np
df = pd.read_csv(io.StringIO("""col1   | type   | date_1 | date_2 | date_3 
ab     |   A    |  -10   |    --    |  -10
ab     |   B    |  100   |   99   |  -12
cd     |   A    |   0    |  -25   |   6
cd     |   B    |  -1    |   8    |  -34
ef     |   A    |  -98   |  -9    |   0
ef     |   B    |  -7    |  -2    |   0
gh     |   A    |  -22   |  0    |   -3
gh     |   B    |  -75   |  0    |   -1

"""), sep="\s+\|\s+", engine="python").replace("--", "", regex=True)

# reshape dataframe so it's in better structure for steps
dfs = df.set_index(["col1","type"]).unstack(1)

# step 1,  identify all -ve values
a = dfs.replace("", 0).astype(int).lt(0).values
# step 2, keep where negative for type A & B,  note 2 relates to len(["A","B"])
ap = a.reshape((a.shape[0]*a.shape[1])//2, 2).all(axis=1)
a = np.repeat(ap,2).reshape(a.shape)

# step 3
# B are odd columns...
bcol = [bcol for bcol in range(a.shape[1]) if bcol%2==1]
# if A&B are both -ve for first date,  remove B value for other dates
# logic: a. A&B both -ve: a[:,[0,1]].all(axis=1),2)
#        b. logical and(not(A&B -ve), (B -ve))
a[:,bcol[1:]] = a[:,bcol[1:]]&np.repeat(~a[:,[0,1]].all(axis=1),2).reshape(len(dfs),2)

# rebuild df with truth array built for step 1&2&3
dfs.loc[:] = np.where(a, dfs, "")

# back to original shape...
df = dfs.stack().reset_index()

  col1 type date_1 date_2 date_3
0   ab    A                  -10
1   ab    B                  -12
2   cd    A                     
3   cd    B                     
4   ef    A    -98     -9       
5   ef    B     -7              
6   gh    A    -22            -3
7   gh    B    -75              
# col A, blanks & negative
a = (((dfs.columns.get_level_values(1)=="A") 
 & dfs.replace("",0).astype(int).le(0)) |
# col B, only negative
((dfs.columns.get_level_values(1)=="B") 
 & dfs.replace("",0).astype(int).lt(0))).values