我有一个相当复杂的数据结构,即熊猫数据框中的字典。假设我有这个数据帧。
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个词典,以便同时跟踪数据,刺激和试验。我不知道这首先是不幸的。
答案 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]}, {}])
。
然后,您可以拥有stimulus
和trial
的数据框:
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.5
和65
。在这种特殊情况下,这并不会改变中位数,但您应该考虑是否要考虑数据中的多个副本。我的代码包含它们,因此如果您不想要它们,则必须调整代码。
编辑:
关于不同刺激的子集,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