Python pandas pyhaystack

Python pandas pyhaystack

我正在使用一个名为 pyhaystack 的模块从基于 'tags.' Python 的楼宇自动化系统检索数据 (rest API) 将 return 的字典数据。我正在尝试将 pandas 与下面的 If Else 语句一起使用,但我遇到了问题。 pyhaystack 可以很好地获取数据...

这将我连接到自动化系统:(工作正常)

from pyhaystack.client.niagara import NiagaraHaystackSession
import pandas as pd

session = NiagaraHaystackSession(uri='http://0.0.0.0', username='Z', password='z', pint=True)

此代码找到名为 'znt' 的标签,将字典转换为 Pandas,并过滤时间:(对这两个点工作得很好)

znt = session.find_entity(filter_expr='znt').result
znt = session.his_read_frame(znt, rng= '2018-01-01,2018-02-12').result
znt = pd.DataFrame.from_dict(znt)


znt.index.names=['Date']
znt = znt.fillna(method = 'ffill').fillna(method = 'bfill').between_time('08:00','17:00')

我最感兴趣的是列名,最终我想要Python到return根据条件命名的列:

print(znt.columns)
print(znt.values)

Returns:

Index(['C.Drivers.NiagaraNetwork.Adams_Friendship.points.A-Section.AV1.AV1ZN~2dT', 'C.Drivers.NiagaraNetwork.points.A-Section.AV2.AV2ZN~2dT'], dtype='object')

[[ 65.9087  66.1592]
 [ 65.9079  66.1592]
 [ 65.9079  66.1742]
 ..., 
 [ 69.6563  70.0198]
 [ 69.6563  70.2873]
 [ 69.5673  70.2873]]

我对 Pandas 数据框的这个名称最感兴趣。 C.Drivers.NiagaraNetwork.Adams_Friendship.points.A-Section.AV1.AV1ZN~2dT

对于我的两个数组,我为数据框中的数据减去 70 的值。 (工作正常)

znt_sp = 70

deviation = znt - znt_sp

deviation = deviation.abs()

deviation

这就是我在 Pandas 中被绊倒的地方。如果偏差大于四,我希望​​ Python 打印列的名称,否则打印此区域为正常。任何提示将不胜感激..

if (deviation > 4).any():
    print('Zone %f does not make setpoint' % deviation)

else:
    print('Zone %f is Normal' % deviation)

Pandas 中的列名称是: C.Drivers.NiagaraNetwork.Adams_Friendship.points.A-Section.AV1.AV1ZN~2dT

解法:
您可以遍历 columns

for col in df.columns:
    if (df[col] > 4).any(): # or .all if needed 
        print('Zone %s does not make setpoint' % col)
    else:
        print('Zone %s is Normal' % col)

或者定义一个函数并使用apply

def _print(x):
    if (x > 4).any():
        print('Zone %s does not make setpoint' % x.name)
    else:
        print('Zone %s is Normal' % x.name)

df.apply(lambda x: _print(x))
# you can even do
[_print(df[col]) for col in df.columns]

建议: 也许你会将结果保存在另一个结构中,将函数更改为 return 一个布尔系列 "is normal":

def is_normal(x):
    return not (x > 4).any()

s = df.apply(lambda x: is_normal(x))

# or directly
s = df.apply(lambda x: not (x > 4).any())

它将 return 一个系列 s 其中 index 是您的 df 的列名, values 是一个与您的条件相对应的布尔值。

然后您可以使用它来获取所有 Normal 列名称 s[s].index 或 non-normal s[~s].index

例如:我只想要 df 的普通列:df[s[s].index]


一个完整的例子
例如,我将使用条件与您不同的样本 df(我检查是否没有元素低于 4 - 正常,否则不设定设定值)

df = pd.DataFrame(dict(a=[1,2,3],b=[2,3,4],c=[3,4,5])) # A sample

print(df)
   a  b  c
0  1  2  3
1  2  3  4
2  3  4  5

你的用例:打印是否正常 - 解决方案

for col in df.columns:
if (df[col] < 4).any():
    print('Zone %s does not make setpoint' % col)
else:
    print('Zone %s is Normal' % col)

结果

Zone a is Normal
Zone b is does not make setpoint
Zone c is does not make setpoint

举例说明我的建议is_normal列保持在一个系列中

s = df.apply(lambda x: not (x < 4).any()) # Build the series
print(s)

a     True
b     False
c     False
dtype: bool


print(df[s[~s].index]) #Falsecolumns df
   b  c
0  2  3
1  3  4
2  4  5


print(df[s[s].index]) #Truecolumns df
   a
0  1
1  2
2  3

我认为 DataFrame 是处理您想要的内容的好方法。 从 znt 开始,您可以在那里进行所有计算:

deviation = znt - 70
deviation = deviation.abs()

# and the cool part is filtering in the df
problem_zones = 
    deviation[deviation['C.Drivers.NiagaraNetwork.Adams_Friendship.points.A-
    Section.AV1.AV1ZN~2dT']>4]

您可以玩这个并想出一种遍历列的方法,例如:

for each in df.columns:
    # if in this column, more than 10 occurences of deviation GT 4...
    if len(df[df[each]>4]) > 10:
        print('This zone have a lot of troubles : ', each)

编辑

我喜欢向 DataFrame 添加列,而不是仅仅构建一个外部系列。

df[‘error_for_a’] = df[a] - 70

这打开了可能性并将所有内容放在一起。可以使用

df[df[‘error_for_a’]>4]

同样,all() 或 any() 可能很有用,但在现实生活中,当出现一定数量的错误时,我们可能需要触发“故障检测”。

如果日程安排在上午 8 点设置为“占用”....也许第一个条目不正确....(即使情况在 30 分钟后好转,任何条目都会触发错误)。另一种情况是一个错误很小的会议室......但是一旦有人在里面......事情就会变糟(all()不会看到)。