【问题标题】:create n*n DataFrame using custom function使用自定义函数创建 n*n DataFrame
【发布时间】:2019-03-05 21:10:08
【问题描述】:

我有如下所示的列:

  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 函数很重要,因为这是简单的示例函数。

【问题讨论】:

  • 您介意向我们展示您的循环,以便我们更好地理解您使用的逻辑吗?您使用的是名称 len() 吗?为什么你有ZceZcef?最后一个是从哪里来的?
  • 对不起输入错误..我更正了它
  • 请在我更新的答案中查看时间。
  • @user32185 感谢您的更新,我想要一些可以用我的真实函数替换 len_mul 函数的东西。
  • 我明白了。我只是想强调一点,矢量解决方案更快;)

标签: python pandas optimization


【解决方案1】:

使用您的自定义函数:

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

【讨论】:

  • 其实我想使用一些自定义函数,这样我就可以替换那个自定义函数
  • 感谢您的宝贵时间和帮助
【解决方案2】:

让我们将此作为详细的评论。我认为这主要取决于您的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 的第二个解决方案,我的速度慢了 2 倍。第一种解决方案分别慢了 311 倍和 154 倍。

【讨论】:

    【解决方案3】:

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

    示例用法:

    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)
    

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

    希望对你有帮助!

    【讨论】:

    • 还有2个循环。
    猜你喜欢
    • 2017-11-30
    • 1970-01-01
    • 1970-01-01
    • 2018-04-15
    • 2019-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-05
    相关资源
    最近更新 更多