使用自定义函数创建n * n DataFrame

时间:2019-03-04 13:24:16

标签: python pandas optimization

我有如下所示的列:

  Data
0    A
1   Av
2  Zcef

我想要使用类似的功能来输出愿望

def len_mul(a,b):
    return len(a) * len(b)

此功能可以替换

Data  A  Av  Zcef            
A     1   2    4
Av    2   4    8
Zcef   4  8    16

我可以使用for循环来执行此操作,但是我不想使用for循环。
我正在尝试使用pd.crosstab,但仍停留在aggfunc

len_mul 函数很重要,因为这是简单起见的示例函数。

3 个答案:

答案 0 :(得分:3)

使用自定义功能:

def len_mul(a,b):
    return len(a) * len(b)

idx = pd.MultiIndex.from_product([df['Data'], df['Data']])
df_out = pd.Series(idx.map(lambda x: len_mul(*x)), idx).unstack()
df_out

输出:

     A  Av  Zcef
A     1   2     4
Av    2   4     8
Zcef  4   8    16

这是来自@piRSquared SO Post


您可以将np.outer与pd.DataFrame构造函数一起使用:

lens = df['Data'].str.len()
pd.DataFrame(np.outer(lens,lens), index = df['Data'], columns=df['Data'])

输出:

Data  A  Av  Zcef
Data             
A     1   2     4
Av    2   4     8
Zcef  4   8    16

答案 1 :(得分:0)

让我们将此作为详尽的评论。我认为这主要取决于您的len_mul函数。如果您想做与问题完全相同的方法,则可以使用一些线性代数。特别是将一个矩阵nxq与一个矩阵qxm相乘得到一个矩阵nxm的事实。

import pandas as pd
import numpy as np

df = pd.DataFrame({"Data":["A", "Av", "Zcef"]})
# this is the len of every entries
v = df["Data"].str.len().values
# this reshape as a (3,1) matrix
v.reshape((-1,1))
# this reshape as a (1,3) matrix
v.reshape((1,-1))
#
arr = df["Data"].values
# this is the matrix multiplication
m = v.reshape((-1,1)).dot(v.reshape((1,-1)))
# your expected output
df_out = pd.DataFrame(m,
                   columns=arr,
                   index=arr)

更新

我同意,Scott Boston解决方案适用于自定义函数的一般情况。但是我认为您应该寻找一种将函数转换为使用线性代数可以完成的功能的方法。

有一些时间:

import pandas as pd
import numpy as np
import string
alph = list(string.ascii_letters)

n = 10000
data = ["".join(np.random.choice(alph,
                                 np.random.randint(1,10))) 
        for i in range(n)]
data = sorted(list(set(data)))
df = pd.DataFrame({"Data":data})


def len_mul(a,b):
    return len(a) * len(b)

斯科特波士顿第一解决方案

%%time
idx = pd.MultiIndex.from_product([df['Data'], df['Data']])
df_out1 = pd.Series(idx.map(lambda x: len_mul(*x)), idx).unstack()

CPU times: user 1min 32s, sys: 10.3 s, total: 1min 43s
Wall time: 1min 43s

斯科特波士顿第二解决方案

%%time
lens = df['Data'].str.len()
arr = df['Data'].values
df_out2 = pd.DataFrame(np.outer(lens,lens),
                       index=arr,
                       columns=arr)

CPU times: user 99.7 ms, sys: 232 ms, total: 332 ms
Wall time: 331 ms

矢量解

%%time
v = df["Data"].str.len().values
arr = df["Data"].values
m = v.reshape((-1,1)).dot(v.reshape((1,-1)))
df_out3 = pd.DataFrame(m,
                       columns=arr,
                       index=arr)

CPU times: user 477 ms, sys: 188 ms, total: 666 ms
Wall time: 666 ms

结论:

明显的赢家是斯科特·波士顿(Scott Boston)第二解决方案,速度慢了两倍。第一种解决方案的速度分别慢了311倍和154倍。

答案 2 :(得分:-1)

我的建议是使用列表理解而不是循环来构建数组。
这样,您之后便可以轻松地创建一个数据框。

用法示例:

import pandas as pd

array = ['A','B','C']

def function (X):

    return X**2

L = [[function(X) for X in pd.np.arange(3)] for Y in pd.np.arange(3)]
L
>>> [[0, 1, 4], [0, 1, 4], [0, 1, 4]]

pd.DataFrame(L, columns=array, index=array)

enter image description here

上面有一些文字:https://www.pythonforbeginners.com/basics/list-comprehensions-in-python

希望有帮助!