从字典列表创建Dataframe,而不使用pd.concat()

时间:2017-03-29 13:59:08

标签: python performance pandas dictionary dataframe

我的数据结构是numpy数组的字典,看起来像这样:

metric_one = 
{0: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
1: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
2: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
3: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])}

metric_two = 
{0: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
1: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
2: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
3: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])}

使用以下标签:

['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']

我希望有一个如下所示的数据框:

   0  1  2  3
a  0  0  0  0
b  1  1  1  1
c  2  2  2  2
d  3  3  3  3
e  4  4  4  4
f  5  5  5  5
g  6  6  6  6
h  7  7  7  7
i  8  8  8  8
j  9  9  9  9
a  0  0  0  0
b  1  1  1  1
c  2  2  2  2
d  3  3  3  3
e  4  4  4  4
f  5  5  5  5
g  6  6  6  6
h  7  7  7  7
i  8  8  8  8
j  9  9  9  9

我可以通过将每个字典转换为数据帧然后将它们与pd.concat()连接来实现。然而,这真的很慢,特别是当连接的dicionaries增长时(我需要连接其中的20个)。从分析开始,似乎在连接之前创建单个数据帧实际上占用了大部分时间。因此,我想知道是否有更好的方法来做到这一点,例如将字典以聪明的方式重新排列成一个包含所有字典的大数据结构(可能在列表中?可能在一个大的指示中?)这样我们就可以了通过将这个大数据结构传递给构造函数来构建一个数据帧。

谢谢!

2 个答案:

答案 0 :(得分:1)

假设

metrics = [metric_one, metric_two]
idx = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']

仅使用numpy

lol = [list(np.concatenate([m[i] for m in metrics])) for i in range(4)]
np.array(lol).T
pd.DataFrame(np.array(lol).T, idx * len(metrics))

天真时间测试

enter image description here

答案 1 :(得分:0)

如果您的词典具有相同的形状且具有相同的键,您可以执行以下操作:

# setup dummy data
metric_one = {0: np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
    1: np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
    2: np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
    3: np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])}

metric_two = {0: np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
    1: np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
    2: np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
    3: np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])}

labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']

# store metrics in one list to iterate over
dicts = [metric_one, metric_two]

# define helper function to concat numpy arrays
def iter_key(key, dicts):
    return np.concatenate([sub_dict[key] for sub_dict in dicts])

merged = {key: iter_key(key, dicts) for key in metric_one.keys()}

df = pd.DataFrame(merged, index=labels * len(dicts))
print(df)

    0   1   2   3
a   0   0   0   0
b   1   1   1   1
c   2   2   2   2
d   3   3   3   3
e   4   4   4   4
f   5   5   5   5
g   6   6   6   6
h   7   7   7   7
i   8   8   8   8
j   9   9   9   9
a   0   0   0   0
b   1   1   1   1
c   2   2   2   2
d   3   3   3   3
e   4   4   4   4
f   5   5   5   5
g   6   6   6   6
h   7   7   7   7
i   8   8   8   8
j   9   9   9   9

首先合并dicts比连接pandas数据帧要快。您可以在下面找到20个词组的时间:

%%timeit
dicts = [metric_one, metric_two]  * 10
def iter_key(key, dicts):
    return np.concatenate([sub_dict[key] for sub_dict in dicts])

merged = {key: iter_key(key, dicts) for key in metric_one.keys()}

df = pd.DataFrame(merged, index=labels * len(dicts))

>>> 1000 loops, best of 3: 630 µs per loop

这里是concat的时间:

%%timeit
dicts = [metric_one, metric_two]  * 10
df = pd.concat([pd.DataFrame(sub_dict, index=labels) for sub_dict in dicts])

>>> 100 loops, best of 3: 13.6 ms per loop

合并第一种方法在这里大约快20倍。