【问题标题】:Python: "Binning" subarraysPython:“分箱”子数组
【发布时间】:2020-01-31 22:02:08
【问题描述】:

我正在寻求根据行的第一个元素对数据行进行分箱。

我的数据是这样的:

[[Temperature, value0, value1, ... value249]
 [Temperature, ...
]

也就是说:每行的第一个元素是温度值,其余的行是信号的时间轨迹。

我想做一个这种形状的数组:

[Temperature-bin,[[values]
                  [values]
                     ... ]]
 Next Temp.-bin, [[values]
                  [values]
                     ... ]]
...
]

原始数据数组中的行应在相应温度箱的子数组中排序。

data= np.array([values]) # shape is [temp+250 timesteps,400K]
temp=data[0]

start=23000
end=380000

tempmin=np.min(temp[start:end])
tempmax=np.max(temp[start:end])

binsize=1
bincenters=np.arange(np.round(tempmin),np.round(tempmax)+1,binsize)

binneddata=np.empty([len(bincenters),2])

for i in np.arange(len(temp)):
    binneddata[i]=[bincenters[i],np.array([])]

我希望得到一个如上所述的结果数组,其中每一行都由 bin 的平均温度 (bincenters[i]) 和时间轨迹数组组成。 Python 给了我一个关于“用序列设置数组元素”的错误。 我之前可以在另一个脚本中创建这种由不同数据类型组成的数组,但我必须在那里专门定义它,在这种情况下这是不可能的,因为我正在处理数十万行数据的文件.同时,我想使用尽可能多的内置函数和尽可能少的循环,因为我的计算机已经花费了一些时间来处理这种大小的文件。

感谢您的意见,

雷帕克

【问题讨论】:

  • 你说的时间轨迹是什么意思?
  • 我的意思是一系列值,就像示波器得到的曲线。我想指出,数据文件中的一行具有不同类型的数据,即 250 个值是该示波器曲线的连续片段,然后还有更多不同类型的数字(例如:温度)。
  • 您似乎在尝试像使用数据表一样使用 NumPy 数组,但这并不是 NumPy 的最佳用途。您可能会更好地为 bin 和数据使用单独的数组,或者使用 pandas 数据框,或者使用字典将 bin 映射到数据,或者使用其他一些数据结构。这将有助于了解您对这个提议的阵列的目标是什么。
  • 稍后我想对子数组(分箱数据)做不同的事情。一件事是在每个子阵列中添加所有线并拟合结果曲线,但还要计算箱中的事件,比较子阵列的大小......我还不确定,还有什么,但它将始终在一个子阵列中处理数据,然后将其结果与温度进行比较。

标签: python pandas numpy dataframe sub-array


【解决方案1】:

首先:感谢 kwinkunks 提供使用 pandas 数据框的提示。 我找到了使用此功能的解决方案。

分箱现在是这样完成的:

tempmin=np.min(temp[start:end])
tempmax=np.max(temp[start:end])

binsize=1
bincenters=np.array(np.arange(np.round(tempmin),np.round(tempmax)+1,binsize))
lowerbinedges=np.array(bincenters-binsize/2)
higherbinedges=np.array(bincenters+binsize/2)

allbinedges=np.append(lowerbinedges,higherbinedges[-1])

temp_pd=pd.Series(temp[start:end])
traces=pd.Series(list(data[start:end,0:250]))


tempbins=pd.cut(temp_pd,allbinedges,labels=bincenters)

df=pd.concat([temp_pd,tempbins,traces], keys=['Temp','Bincenter','Traces'], axis=1)

通过定义箱(在这种情况下为偶数)。变量“tempbins”与 temp(“原始”温度)具有相同的形状,并将每一行数据分配给某个 bin。

实际分析非常简短。开始于:

rf=pd.DataFrame({'Bincenter': bincenters})

结果框(“rf”)从 bincenters 开始(作为稍后图中的 x 轴),并简单地为所需结果添加列。

df[df.Bincenter==xyz] 

我只能从 df 中选择那些我希望在所选 bin 中拥有的数据行。

就我而言,我对实际时间轨迹不感兴趣,但对总和或平均值不感兴趣,所以我使用 lambda 函数,它遍历 rf 的行并搜索 df 中的每一行,它具有那里的“Bincenter”中的值相同。

rf['Binsize']=rf.apply(lambda row: len(df.Traces[df.Bincenter==row.Bincenter]), axis=1)
rf['Trace_sum']=rf.apply(lambda row: sum(df.Traces[df.Bincenter==row.Bincenter]), axis=1)

有了这些,在结果帧 rf 中添加了另一列,用于计算轨迹的总和以及 bin 中的行数。

我在 rf.Trace_sum 中进行了一些拟合,而我在 pandas 中没有这样做。

不过,数据框在这里非常有用。我用 odr 来装这样的

for i in binnumber:
    fitdata=odr.Data(time[fitstart:],rf.Trace_sum.values[i][fitstart:])
    ... some more fit stuff here...

并将fitresults保存在

lifetimefits=pd.DataFrame({'lifetime': fitresult[:,1], 'sd_lifetime':fitresult[:,4]})

最后将它们添加到结果框中

rf=pd.concat([rf,lifetimefits],axis=1)
rf[['Bincenter','Binsize','lifetime','sd_lifetime']].to_csv('results.csv', header=True, index=False)

输出类似

Out[78]: 
    Bincenter  Binsize  ...   lifetime  sd_lifetime
0       139.0     4102  ...  38.492028     2.803211
1       140.0     4252  ...  33.659729     2.534872
2       141.0     3785  ...  31.220312     2.252104
3       142.0     3823  ...  29.391562     1.783890
4       143.0     3808  ...  40.422578     2.849545

我希望,这个解释可以帮助其他人不要浪费时间,用 numpy.再次感谢 kwinkunks 对使用 pandas DataFrame 的非常有用的建议。

最好, 雷帕克

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-15
    • 2018-04-06
    • 1970-01-01
    • 1970-01-01
    • 2017-07-31
    • 2013-06-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多