将带有元组条目的DataFrame解压缩到单独的DataFrame中

时间:2018-01-10 10:15:01

标签: python pandas iterable-unpacking

我写了一个小班来通过bootstrap计算一些统计数据而无需替换。对于那些不熟悉这种技术的人,你得到一些数据的n个随机子样本,计算每个子样本的所需统计量(比如中位数),然后比较子样本的值。这使您可以获得数据集上获得的中位数的方差度量。

我在一个类中实现了它,但是将它减少到由以下函数给出的MWE

import numpy as np
import pandas as pd

def bootstrap_median(df, n=5000, fraction=0.1):
    if isinstance(df, pd.DataFrame):
        columns = df.columns
    else:
        columns = None
    # Get the values as a ndarray
    arr = np.array(df.values)

    # Get the bootstrap sample through random permutations
    sample_len = int(len(arr)*fraction)
    if sample_len<1:
        sample_len = 1
    sample = []
    for n_sample in range(n):
        sample.append(arr[np.random.permutation(len(arr))[:sample_len]])
    sample = np.array(sample)

    # Compute the median on each sample
    temp = np.median(sample, axis=1)

    # Get the mean and std of the estimate across samples
    m = np.mean(temp, axis=0)
    s = np.std(temp, axis=0)/np.sqrt(len(sample))

    # Convert output to DataFrames if necesary and return
    if columns:
        m = pd.DataFrame(data=m[None, ...], columns=columns)
        s = pd.DataFrame(data=s[None, ...], columns=columns)
    return m, s

此函数返回在每个bootstrap样本上计算的中位数的平均值和标准差。

现在考虑这个例子DataFrame

data  = np.arange(20)
group = np.tile(np.array([1, 2]).reshape(-1,1), (1,10)).flatten()
df    = pd.DataFrame.from_dict({'data': data, 'group': group})
print(df)
print(bootstrap_median(df['data']))

打印

    data  group
0      0      1
1      1      1
2      2      1
3      3      1
4      4      1
5      5      1
6      6      1
7      7      1
8      8      1
9      9      1
10    10      2
11    11      2
12    12      2
13    13      2
14    14      2
15    15      2
16    16      2
17    17      2
18    18      2
19    19      2

(9.5161999999999995, 0.056585753613431718)

到目前为止很好,因为bootstrap_median会返回两个元素的tuple。但是,如果我在groupby

之后执行此操作
In: df.groupby('group')['data'].apply(bootstrap_median)

Out:
group
1     (4.5356, 0.0409710449952)
2    (14.5006, 0.0403772204095)

每个单元格中的值都是tuple s,正如apply所期望的那样。我可以通过迭代这样的元素将结果解压缩到两个DataFrame中:

index = []
data1 = []
data2 = []
for g, (m, s) in out.iteritems():
    index.append(g)
    data1.append(m)
    data2.append(s)
dfm = pd.DataFrame(data=data1, index=index, columns=['E[median]'])
dfm.index.name = 'group'
dfs = pd.DataFrame(data=data2, index=index, columns=['std[median]'])
dfs.index.name = 'group'

从而

In: dfm
Out:
       E[median]
group  
1         4.5356
2        14.5006

In: dfs
Out:
           std[median]
group  
1      0.0409710449952
2      0.0403772204095

这有点麻烦,我的问题是,如果有更多的pandas本地方式来解压缩&#34;一个数据框,其值是元组到单独的DataFrame&#39;

This question似乎有关系,但它涉及字符串正则表达式替换而不是解包真正的元组。

1 个答案:

答案 0 :(得分:1)

我认为你需要改变:

return m, s

为:

return pd.Series([m, s], index=['m','s'])

然后得到:

df1 = df.groupby('group')['data'].apply(bootstrap_median)
print (df1)
group   
1      m     4.480400
       s     0.040542
2      m    14.565200
       s     0.040373
Name: data, dtype: float64

因此可以选择xs

print (df1.xs('s', level=1))
group
1    0.040542
2    0.040373
Name: data, dtype: float64

print (df1.xs('m', level=1))
group
1     4.4804
2    14.5652
Name: data, dtype: float64

如果需要一列DataFrame添加to_frame

df1 = df.groupby('group')['data'].apply(bootstrap_median).to_frame()
print (df1)
              data
group             
1     m   4.476800
      s   0.041100
2     m  14.468400
      s   0.040719

print (df1.xs('s', level=1))
           data
group          
1      0.041100
2      0.040719

print (df1.xs('m', level=1))
          data
group         
1       4.4768
2      14.4684