Python:通过熊猫值的字典键值的平均值

时间:2017-11-13 15:27:10

标签: python python-3.x pandas dictionary median

我有一个相当复杂的数据结构,即熊猫数据框中的字典。假设我有这个数据帧。

trials_ = [1,2,1,2]
stimul_ = [1,1,2,2]
data_ = [[{'peak_voltage': [30.5, 65], 'Spikecount': [2]}], [{'peak_voltage': [30.5, 65, 30], 'Spikecount': [3]}], [{'peak_voltage': [20.1], 'Spikecount': [1]}], 'NaN']
featve  = pd.DataFrame({'trial': trials_, 'stimulus': stimul_, 'data': data_})
featve

    data                                                stimulus    trial
0   [{'peak_voltage': [30.5, 65], 'Spikecount': [2]}]   1           1 
1   [{'peak_voltage': [30.5, 65, 30], 'Spikecount'...   1           2
2   [{'peak_voltage': [20.1], 'Spikecount': [1]}]       2           1
3   NaN                                                 2           2

我现在想要在我的数据'中计算字典中每个关键元素的中位数和25%/ 75%四分位数。所有试验中每个刺激的列(此处为 peak_voltage Spikecount )。

中位数的一个例子: 当在所有试验中应用刺激1时,我想要中值 peak_voltage 值[30.5,65,20.1] - > 30.5。当施加刺激2时[30.5,65,30,NaN] - > 30.5。对于 Spikecount 当然也是如此。

说实话,我不知道从哪里开始。如果我只想计算中位数而不管模拟,我只想使用。

featve.data.median

但这不是我想要的。另外,如果我没有字典但只有数字,我会使用像

这样的东西
featve.groupby('stimulus').data.apply(np.nanmedian)  

但在我的情况下,我可以用熊猫表中的字典做什么?

编辑1

我有10个刺激,每个刺激16次,共计160行。字典是名为EFEL的工具箱的输出,我用它来查找数据轨迹的某些特征(例如神经元动作电位峰值的时间)。我决定在熊猫数据框中组织最终的160个词典,以便同时跟踪数据,刺激和试验。我不知道这首先是不幸的。

2 个答案:

答案 0 :(得分:1)

根据您的要求,我建议您重新构建数据框。而不是使用:

构建featve
data_ = [[{'peak_voltage': [30.5, 65], 'Spikecount': [2]}], [{'peak_voltage': [30.5, 65, 30], 'Spikecount': [3]}], [{'peak_voltage': [20.1], 'Spikecount': [1]}], 'NaN']

data_ = {'peak_voltage': [30.5, 65, 30.5, 65, 30, 20.1, np.nan], 'Spikecount': [2,2,3,3,3,1, np.nan], 'trials': [1,1,2,2,2,1,2], 'stimulus': [1,1,1,1,1,2,2]}
featve = pd.DataFrame(data_)

结果是以下DataFrame:

   Spikecount  peak_voltage  stimulus  trials
0         2.0          30.5         1       1
1         2.0          65.0         1       1
2         3.0          30.5         1       2
3         3.0          65.0         1       2
4         3.0          30.0         1       2
5         1.0          20.1         2       1
6         NaN           NaN         2       2

在此DataFrame上,您可以像平常一样对中位数进行分组和计算。

e.g

featve.groupby('stimulus').peak_voltage.meadian()
stimulus
1    30.5
2    20.1
Name: peak_voltage, dtype: float64

<强>更新

我理解对没有&#34; Nice&#34;数据。给定一个遵循data_格式的严格构造,您可以使用defaultdict来获得更好的数据帧。

dict_data = defaultdict(list)

for idx in range(len(data_)):
     if isinstance(data_[idx], list):
         for sub in data_[idx]:
             repeats = len(sub['peak_voltage'])
             data_dict['peak_voltage'] += sub['peak_voltage']
             data_dict['Spikecount'] += sub['Spikecount'] * repeats
             data_dict['trial'] += [trials_[idx]] * repeats
             data_dict['stimulus'] += [stimul_[idx]] * repeats
     else:
         data_dict['peak_voltage'].append('NaN')
         data_dict['Spikecount'].append('NaN')
         data_dict['trial'] += [trials_[idx]]
         data_dict['stimulus'] += [stimul_[idx]]

pd.DataFrame(data_dict)
  Spikecount peak_voltage  stimulus  trial
0          2         30.5         1      1
1          2           65         1      1
2          3         30.5         1      2
3          3           65         1      2
4          3           30         1      2
5          1         20.1         2      1
6        NaN          NaN         2      2

答案 1 :(得分:0)

首先,我不确定您为什么要将您的dicionaries放入列表中,但我建议您在没有它们的情况下使用您的数据版本。此外,如果您的大多数数据都是字典形式,那么我建议也以字典的形式提供缺失的数据。完成后,您可以将data_放入数据框中。所以

my_data = pd.DataFrame([{'peak_voltage': [30.5, 65], 'Spikecount': [2]}, {'peak_voltage': [30.5, 65, 30], 'Spikecount': [3]}, {'peak_voltage': [20.1], 'Spikecount': [1]}, {}])

然后,您可以拥有stimulustrial的数据框:

stimulus_trial_df = pd.DataFrame({'trial': trials_, 'stimulus': stimul_})

接下来,您可以对my_data

的属性进行stiumulus_trial_df切片

subset1 = my_data.loc[stimulus_trial_df['stimulus']==1]

请注意,您必须确保两个数据框具有一致的索引才能使其正常工作。

获得subset1后,您可以展平其中的列:

spikecount_agg= [spikecount for row in subset1['Spikecount'] for spikecount in row]

最后,您可以在展平列上执行任何操作:

import statistics
current_median = statistics.median(spikecount_agg)

最后一点:您提出了问题[30.5, 65, 20.1] -> 30.5,但您的数据有两份30.565。在这种特殊情况下,这并不会改变中位数,但您应该考虑是否要考虑数据中的多个副本。我的代码包含它们,因此如果您不想要它们,则必须调整代码。

编辑: 关于不同刺激的子集,for循环应该足够。如果你有一个包含独特刺激的物体,你可以绕过它;如果您不这样做,可以使用unique_stimuli = set(stimul_)

生成它
for stimulus in unique_stimuli:
   subset = my_data.loc[stimulus_trial_df['stimulus']==stimulus]
   #do what you want with subset