Python 应用函数在groupby中未按预期工作

Python 应用函数在groupby中未按预期工作,python,pandas,pandas-groupby,pandas-apply,Python,Pandas,Pandas Groupby,Pandas Apply,我有一个数据框,看起来像: ID | timestamp |Phase| current ======================================== 001 | 2020-09-20 07:00 | A | 1.4 001 | 2020-09-20 07:00 | B | 2.0 001 | 2020-09-20 07:00 | C | 1.6 002 | 2020-09-20 09:00 | A | 1.4 002

我有一个数据框,看起来像:

ID    |     timestamp    |Phase| current
========================================
001   | 2020-09-20 07:00 | A   | 1.4
001   | 2020-09-20 07:00 | B   | 2.0
001   | 2020-09-20 07:00 | C   | 1.6
002   | 2020-09-20 09:00 | A   | 1.4
002   | 2020-09-20 09:00 | B   | 1.23
002   | 2020-09-20 09:00 | C   | 1.46
我需要计算每个ID/时间戳分组阶段的百分比差异,因此我创建了一个groupby:

imbalanced = df.groupby(['timestamp','ID']).apply(calcImbalance)
下面是calcImbalance:

def calcImbalance(pole):
    
        phA = pole.loc[pole['Phase'] == 'A']['current'].astype('float')
        phB = pole.loc[pole['Phase'] == 'B']['current'].astype('float')
        phC = pole.loc[pole['Phase'] == 'C']['current'].astype('float')
        
        imb = abs((phA-phB)/phB)
        print ('imb:', imb)
        if imb  >= 0.3:
            return pole
        imb = abs((phB-phA)/phA)
        if imb >= 0.3:
            return pole
        imb = abs((phA-phC)/phC)
        if imb >= 0.3:
            return pole
        imb = abs((phC-phA)/phA)
        if imb >= 0.3:
            return pole
但这只是打印:

imb: 2661   NaN
2662   NaN
Name: Amps, dtype: float64
imb: 2661   NaN
2662   NaN
Name: Amps, dtype: float64
然后 引发异常:
ValueError:序列的真值不明确。使用a.empty、a.bool()、a.item()、a.any()或a.all()。

我试图做的是创建一个数据帧,只包含df中阶段间差异>30%的实例。我想我是为了一些看起来应该是琐碎的事情而掉进了兔子洞里

在上述示例中,“不平衡”数据帧应包含:

ID    |     timestamp    |Phase| current
========================================
001   | 2020-09-20 07:00 | A   | 1.4
001   | 2020-09-20 07:00 | B   | 2.0

应用功能不会测试B和C阶段之间的不平衡,只有A和B阶段与A和C阶段之间的不平衡

IIUC您可以使用应用功能找到所需的行

df['cng'] = (df.groupby('ID')['current'].pct_change() + 1).groupby(df.ID).cumprod()-1
df[df.groupby('ID')['cng'].transform(lambda x: x.fillna(x.max())) > .30]
输出

   ID         timestamp Phase  current       cng
0   1  2020-09-20 07:00     A      1.4       NaN
1   1  2020-09-20 07:00     B      2.0  0.428571
   ID         timestamp Phase  current
0   1  2020-09-20 07:00     A      1.4
1   1  2020-09-20 07:00     B      2.0
2   1  2020-09-20 07:00     C      1.6
0         NaN
1    0.428571
2   -0.200000
3         NaN
4   -0.121429
5    0.186992
0         NaN
1    1.428571
2    1.142857
3         NaN
4    0.878571
5    1.042857
ph > 1.4 1.5 1.6
imb: 0.06666666666666672
ph > 1.4 1.23 1.46
imb: 0.13821138211382109

timestamp         ID
2020-09-20 07:00  1     None
2020-09-20 09:00  2     None
Name: current, dtype: object

这是怎么回事 查找阶段之间发生更改的组>.30

df[df.groupby('ID')['current'].pct_change().groupby(df.ID).transform('max') > .30]
输出

   ID         timestamp Phase  current       cng
0   1  2020-09-20 07:00     A      1.4       NaN
1   1  2020-09-20 07:00     B      2.0  0.428571
   ID         timestamp Phase  current
0   1  2020-09-20 07:00     A      1.4
1   1  2020-09-20 07:00     B      2.0
2   1  2020-09-20 07:00     C      1.6
0         NaN
1    0.428571
2   -0.200000
3         NaN
4   -0.121429
5    0.186992
0         NaN
1    1.428571
2    1.142857
3         NaN
4    0.878571
5    1.042857
ph > 1.4 1.5 1.6
imb: 0.06666666666666672
ph > 1.4 1.23 1.46
imb: 0.13821138211382109

timestamp         ID
2020-09-20 07:00  1     None
2020-09-20 09:00  2     None
Name: current, dtype: object
这给出了组中的百分比变化

df.groupby('ID')['current'].pct_change()
输出

   ID         timestamp Phase  current       cng
0   1  2020-09-20 07:00     A      1.4       NaN
1   1  2020-09-20 07:00     B      2.0  0.428571
   ID         timestamp Phase  current
0   1  2020-09-20 07:00     A      1.4
1   1  2020-09-20 07:00     B      2.0
2   1  2020-09-20 07:00     C      1.6
0         NaN
1    0.428571
2   -0.200000
3         NaN
4   -0.121429
5    0.186992
0         NaN
1    1.428571
2    1.142857
3         NaN
4    0.878571
5    1.042857
ph > 1.4 1.5 1.6
imb: 0.06666666666666672
ph > 1.4 1.23 1.46
imb: 0.13821138211382109

timestamp         ID
2020-09-20 07:00  1     None
2020-09-20 09:00  2     None
Name: current, dtype: object
每组的累积变化

(df.groupby('ID')['current'].pct_change() + 1).groupby(df.ID).cumprod()
输出

   ID         timestamp Phase  current       cng
0   1  2020-09-20 07:00     A      1.4       NaN
1   1  2020-09-20 07:00     B      2.0  0.428571
   ID         timestamp Phase  current
0   1  2020-09-20 07:00     A      1.4
1   1  2020-09-20 07:00     B      2.0
2   1  2020-09-20 07:00     C      1.6
0         NaN
1    0.428571
2   -0.200000
3         NaN
4   -0.121429
5    0.186992
0         NaN
1    1.428571
2    1.142857
3         NaN
4    0.878571
5    1.042857
ph > 1.4 1.5 1.6
imb: 0.06666666666666672
ph > 1.4 1.23 1.46
imb: 0.13821138211382109

timestamp         ID
2020-09-20 07:00  1     None
2020-09-20 09:00  2     None
Name: current, dtype: object

此解决方案可以检测到什么? 在数据帧中

    ID         timestamp Phase  current  
0  001  2020-09-20 07:00     A      1.4  
1  001  2020-09-20 07:00     B      2.0 
2  001  2020-09-20 07:00     C      1.6 
3  002  2020-09-20 09:00     A      1.4 
4  002  2020-09-20 09:00     B      1.2 
5  002  2020-09-20 09:00     C      2.0 
6  003  2020-09-20 09:00     A      1.4 
7  003  2020-09-20 09:00     B      2.0 
8  003  2020-09-20 09:00     C      1.6 
9  003  2020-09-20 09:00     D      2.0 
使用此解决方案

df['cng'] = (df.groupby('ID')['current'].pct_change() + 1).groupby(df.ID).cumprod()-1
df[df.groupby('ID')['cng'].transform(lambda x: x.fillna(x.max())) > .30]
结果。请注意,
cng
是计算第一行变化的累积乘积

    ID         timestamp Phase  current       cng
0  001  2020-09-20 07:00     A      1.4       NaN
1  001  2020-09-20 07:00     B      2.0  0.428571
3  002  2020-09-20 09:00     A      1.4       NaN
5  002  2020-09-20 09:00     C      2.0  0.428571
6  003  2020-09-20 09:00     A      1.4       NaN
7  003  2020-09-20 09:00     B      2.0  0.428571
9  003  2020-09-20 09:00     D      2.0  0.428571

根据您的代码,这可能有效。这会将电流收集到一个列表中,并将其传递给
calcImbalance
功能

import pandas as pd

dd = {
'ID':[1,1,1,2,2,2],
'timestamp':['2020-09-20 07:00','2020-09-20 07:00','2020-09-20 07:00','2020-09-20 09:00','2020-09-20 09:00','2020-09-20 09:00'],
'Phase':['A','B','C','A','B','C'],
'current':[1.4,1.5,1.6,1.4,1.23,1.46]
}

df = pd.DataFrame(dd)


def calcImbalance(pole):
        
        phA, phB, phC = tuple(pole)  # currents in group
        print('ph >',phA, phB, phC)
        
        imb = abs((phA-phB)/phB)
        print ('imb:', imb)
        if imb >= 0.3:
            return pole
        imb = abs((phB-phA)/phA)
        if imb >= 0.3:
            return pole
        imb = abs((phA-phC)/phC)
        if imb >= 0.3:
            return pole
        imb = abs((phC-phA)/phA)
        if imb >= 0.3:
            return pole
            

gb = df.groupby(['timestamp','ID'])['current'].apply(lambda x:[i for i in x]).apply(calcImbalance) 

print('\n',gb)
输出

   ID         timestamp Phase  current       cng
0   1  2020-09-20 07:00     A      1.4       NaN
1   1  2020-09-20 07:00     B      2.0  0.428571
   ID         timestamp Phase  current
0   1  2020-09-20 07:00     A      1.4
1   1  2020-09-20 07:00     B      2.0
2   1  2020-09-20 07:00     C      1.6
0         NaN
1    0.428571
2   -0.200000
3         NaN
4   -0.121429
5    0.186992
0         NaN
1    1.428571
2    1.142857
3         NaN
4    0.878571
5    1.042857
ph > 1.4 1.5 1.6
imb: 0.06666666666666672
ph > 1.4 1.23 1.46
imb: 0.13821138211382109

timestamp         ID
2020-09-20 07:00  1     None
2020-09-20 09:00  2     None
Name: current, dtype: object
--更新--


根据您发布的更新,这可能不是完整答案,但可能仍有助于获得解决方案。

编辑:此代码回答问题,包括编辑

import pandas as pd


def calc_imbalance(current):
    pairs_to_test = [[0, 1], [0, 2], [1, 2]]
    for pair in pairs_to_test:
        abs_percentage_imbalance = abs((current[pair[0]] - current[pair[1]])/current[pair[1]])
        if abs_percentage_imbalance >= .3:
            return pair
    return []

df = pd.DataFrame([('001', '2020-09-20 07:00', 'A', 1.4),
                   ('001', '2020-09-20 07:00', 'B', 2.0),
                   ('001', '2020-09-20 07:00', 'C', 1.6),
                   ('002', '2020-09-20 09:00', 'A', 1.4),
                   ('002', '2020-09-20 09:00', 'B', 1.23),
                   ('002', '2020-09-20 09:00', 'C', 1.46)],
                  columns=['ID', 'timestamp', 'Phase', 'current'])

df['original_index'] = df.index

all_index_to_keep = []
for _, group in df.groupby(['timestamp', 'ID']).agg(list).reset_index().iterrows():
    index_to_keep = calc_imbalance(group['current'])
    all_index_to_keep += [v for k, v in enumerate(group['original_index']) if k in index_to_keep]
df.drop('original_index', axis=1, inplace=True)
print(df.loc[all_index_to_keep, :])

返回:

    ID         timestamp Phase  current
0  001  2020-09-20 07:00     A      1.4
1  001  2020-09-20 07:00     B      2.0

请根据所示的样本数据,举例说明预期结果。此外,
imb
是一个
pandas.Series
,而不是一个值。进行比较时,
imb>0.3
需要知道您指的是序列中的任何值还是所有值。在示例中,
imb
为空,因此示例没有帮助。在阶段之间,哪一行的更改>0.3?我找不到任何IIUC。抱歉,我的样本数据不正确,没有不平衡>=30%的实例!好的,编辑示例。ID 001阶段A和B有42%的不同。:abs((1.4-2)/1.4)=.42,因此(ID 001应该包含在不平衡的数据框中。感谢您的回答,但出于某种原因,您的回答的第二行引发了一个异常:
ValueError:Length missach:Expected axis有4261个元素,新值有4590个元素,与您在问题中提供的数据框相同?另外,数据框有4590行长,因此我我不知道为什么第二个操作只需要4261,除非这恰好是cng=Nanno的确切数字,以及我正在操作的实际数据帧。它是4590 x 13,我的解决方案无法处理缺少的值(
NaN
)在分组列
ID
中。我认为您可以删除这些行,因为您无法将它们分配给组。