【发布时间】:2014-04-11 22:19:09
【问题描述】:
我正在尝试对使用 Python 的 Pandas.DataFrame 在不同时间改变状态的函数求和(并绘制)总数。例如:
假设我们有 3 个人的状态可以是 a) 什么都没有,b) 有 5 磅的重量,c) 有 10 磅的重量。随着时间的推移,这些人会拿起重量并放下它们。我想绘制所持有的总重量。所以,给定:
我的蛮力尝试:
import pandas as ps
import math
import numpy as np
person1=[3,0,10,10,10,10,10]
person2=[4,0,20,20,25,25,40]
person3=[5,0,5,5,15,15,40]
allPeopleDf=ps.DataFrame(np.array(zip(person1,person2,person3)).T)
allPeopleDf.columns=['count','start1', 'end1', 'start2', 'end2', 'start3','end3']
allPeopleDfNoCount=allPeopleDf[['start1', 'end1', 'start2', 'end2', 'start3','end3']]
uniqueTimes=sorted(ps.unique(allPeopleDfNoCount.values.ravel()))
possibleStates=[-1,0,1,2] #extra state 0 for initialization
stateData={}
comboStates={}
#initialize dict to add up all of the stateData
for time in uniqueTimes:
comboStates[time]=0.0
allPeopleDf['track']=-1
allPeopleDf['status']=-1
numberState=len(possibleStates)
starti=-1
endi=0
startState=0
for i in range(3):
starti=starti+2
print starti
endi=endi+2
for time in uniqueTimes:
def helper(row):
start=row[starti]
end=row[endi]
track=row[7]
if start <= time and time < end:
return possibleStates[i+1]
else:
return possibleStates[0]
def trackHelp(row):
status=row[8]
track=row[7]
if track<=status:
return status
else:
return track
def Multiplier(row):
x=row[8]
if x==0:
return 0.0*row[0]
if x==1:
return 5.0*row[0]
if x==2:
return 10.0*row[0]
if x==-1:#numeric place holder for non-contributing
return 0.0*row[0]
allPeopleDf['status']=allPeopleDf.apply(helper,axis=1)
allPeopleDf['track']=allPeopleDf.apply(trackHelp,axis=1)
stateData[time]=allPeopleDf.apply(Multiplier,axis=1).sum()
for k,v in stateData.iteritems():
comboStates[k]=comboStates.get(k,0)+v
print allPeopleDf
print stateData
print comboStates
随着时间的推移保持体重的图表可能如下所示:
随着时间的推移,强度的总和可能看起来像下面的黑线:
用笛卡尔点定义的黑线:(0,0 lbs),(5,0 lbs),(5,5 lbs),(15,5 lbs),(15,10 lbs),(20 ,10 磅),(20,15 磅),(25,15 磅),(25,20 磅),(40,20 磅)。但是,我很灵活,不一定需要将组合强度线定义为一组笛卡尔点。可以通过以下方式找到独特的时间: 打印列表(set(uniqueTimes).intersection(allNoCountT[1].values.ravel())).sort() ,但我想不出一个巧妙的方法来获取相应的强度值。
我开始使用一个非常丑陋的函数来分解每个“人”的图表,以便所有人同时拥有开始和停止时间(尽管有很多停止和开始时间没有状态改变),然后我可以加起来时间的所有“块”。这很麻烦。必须有一种巧妙的熊猫方式来处理这个问题。如果有人可以提供建议或将我指向另一个我可能错过的 SO,我将不胜感激!
如果我的简化示例不清楚,另一个可能是绘制来自钢琴的声音强度:有许多音符在不同的持续时间以不同的强度演奏。我想要随着时间的推移钢琴的强度总和。虽然我的示例很简单,但我需要一个更接近钢琴歌曲规模的解决方案:每个键有数千个离散强度级别,并且在歌曲过程中有许多键。
编辑--mgab 提供的解决方案的实现:
import pandas as ps
import math
import numpy as np
person1=['person1',3,0.0,10.0,10.0,10.0,10.0,10.0]
person2=['person2',4,0,20,20,25,25,40]
person3=['person3',5,0,5,5,15,15,40]
allPeopleDf=ps.DataFrame(np.array(zip(person1,person2,person3)).T)
allPeopleDf.columns=['id','intensity','start1', 'end1', 'start2', 'end2', 'start3','end3']
allPeopleDf=ps.melt(allPeopleDf,id_vars=['intensity','id'])
allPeopleDf.columns=['intensity','id','timeid','time']
df=ps.DataFrame(allPeopleDf).drop('timeid',1)
df[df.id=='person1'].drop('id',1) #easier to visualize one id for check
df['increment']=df.groupby('id')['intensity'].transform( lambda x: x.sub(x.shift(), fill_value= 0 ))
TypeError: 不支持的操作数类型 -: 'str' 和 'int'
结束编辑
【问题讨论】:
-
什么是'start1'、'end1'等等?次?当权重/音符强度可能发生变化时,您真的只有几次标记时间,还是更像是一个连续体?我的意思是,“start1”标签对您有意义还是只是问题简化的一部分?在我的回答中,我假设您可以将您的数据视为在第二个 23 人 2 将其权重更改为 15...但我们可以对其进行调整...
-
另外,每个列表的初始值是什么意思(
3、4和5)?我认为其余的值代表了那个人在每个时间点所承受的重量,但是看到allPeopleDf.columns=['intensity','id','timeid','time'].的输出后我很困惑尝试解释你的真实数据是如何组织的我们可以调整代码来适应它。 -
继续钢琴示例: startx/endx 指的是一个键以一定强度演奏的开始和结束时间。 start1/end1 可以是每个键以强度 0 播放的时间,start2/end2 可以是每个键以强度 x 播放的时间等。
-
很抱歉与 3、4、5 混淆——这些是应用于最终结果的权重。例如,给定音符 A、B 和 C 的相同强度,也许一个人会更容易听到 C,所以我考虑了一些权重因素。我将把它留在示例中,这样我就不会因为删除它而造成更多混乱,但请随意忽略。
-
答案已编辑。我想现在应该没问题。 :)
标签: python plot pandas time-series dataframe