Python 将系列位转换为十进制整数

Python 将系列位转换为十进制整数,python,performance,pandas,binary,timing,Python,Performance,Pandas,Binary,Timing,我有一个维度(m,n)的熊猫数据框架,其中填充了0和1。 若数据帧的每一行都被视为一个二进制数,那个么我想生成一个以10为基数的整数序列,用该行表示 给定以下尺寸矩阵(m,n),填充0和1: m = int(1e6) n = 5 df = pd.DataFrame(np.random.rand(m,n)).round().astype(int) 我现在使用的方法是: df_asstr = df.astype(str) bin_series = df_asstr.sum(axis=1).asty

我有一个维度(
m
n
)的熊猫数据框架,其中填充了
0
1
。 若数据帧的每一行都被视为一个二进制数,那个么我想生成一个以10为基数的整数序列,用该行表示

给定以下尺寸矩阵(
m
n
),填充
0
1

m = int(1e6)
n = 5
df = pd.DataFrame(np.random.rand(m,n)).round().astype(int)
我现在使用的方法是:

df_asstr = df.astype(str)
bin_series = df_asstr.sum(axis=1).astype(int).astype(str)

def bin_to_int(strnum):
    return int(strnum, 2)

decimal_series = bin_series.astype(str).apply(bin_to_int)
我这里的问题是时机。如果数据帧的长度约为
m=1e3
,则整个过程所需时间不到1秒。然而,当我使用
m=1e6
时,大约需要22秒,我需要运行其中的许多,所以我真的想加快速度

我知道减慢过程的步骤涉及将
数据帧
转换为
str
,即以下几行:

df_asstr = df.astype(str)
bin_series = df_asstr.sum(axis=1).astype(int).astype(str)
decimal_series = bin_series.astype(str).apply(bin_to_int)

有人知道一种更有效的方法来创建十进制整数系列吗??非常感谢

我想这正是你想要的:

(2 ** (np.arange(start = len(df.columns), stop = 0, step = -1)-1) * df).sum(axis =1)

0          1
1         27
2          4
3         11
4         29
5         27
6          3
7         29
说明:

我们想将数据帧的每一列乘以2**x,其中x是它离右侧多远的索引:

2 ** (np.arange(start = len(df.columns), stop = 0, step = -1)-1) 

array([16,  8,  4,  2,  1], dtype=int32)
一旦我们有了这个,我们将数据帧乘以它,在轴上求和=1,得到我们的序列

时间:

你的回答是:

%%timeit
df_asstr = df.astype(str)
bin_series = df_asstr.sum(axis=1).astype(int).astype(str)

def bin_to_int(strnum):
    return int(strnum, 2)

decimal_series = bin_series.astype(str).apply(bin_to_int)

1 loop, best of 3: 20.2 s per loop
这个:

%%timeit
(2 ** (np.arange(start = len(df.columns), stop = 0, step = -1)-1) * df).sum(axis =1)

10 loops, best of 3: 117 ms per loop
编辑:@jezrael回答如下,mul和sum是点积:

df.values.dot((2 ** (np.arange(start = len(df.columns), stop = 0, step = -1)-1)))

10 loops, best of 3: 23.4 ms per loop

您正确地将字符串转换识别为瓶颈。通过将二进制转换为十进制的教科书方法可以避免这些问题。将每列乘以相应的值,并按行求和。对于过时的安装,这将产生约380x的加速比。下面的片段在Jupyter笔记本中记录了两种方法的时间。
df
的设置与第一个代码部分相同

m = int(1e6)
n = 5
df = pd.DataFrame(np.random.rand(m,n)).round().astype(int)

def StatusQuo(df):
    df_asstr = df.astype(str)
    bin_series = df_asstr.sum(axis=1).astype(int).astype(str)

    def bin_to_int(strnum):
        return int(strnum, 2)

    decimal_series = bin_series.astype(str).apply(bin_to_int)
    return decimal_series
%time StatusQuo(df)
# CPU times: user 12.1 s, sys: 103 ms, total: 12.2 s
# Wall time: 12.2 s


def Naive(df):
    n = len(df.columns)
    powers = np.array([2**i for i in range(n-1,-1,-1)])
    df_values = df.mul(powers).sum(axis=1)
return df_values
%time Naive(df)
# CPU times: user 31 ms, sys: 52 ms, total: 83 ms
# Wall time: 32.1 ms
可以将乘积与按位左移位运算符一起使用:

a = df.values
b = a.dot(1 << np.arange(a.shape[-1] - 1, -1, -1))
a=df.values

b=a.dot(1个不错的,mul和sum上的
.dot()
是这里加速的关键,但是
该死,你们很聪明。非常感谢,它工作得很好。
In [157]: %%timeit 
     ...: a = df.values
     ...: b = pd.Series(a.dot(1 << np.arange(a.shape[-1] - 1, -1, -1)), index=df.index)
     ...: 
16.8 ms ± 281 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [158]: %%timeit
     ...: (2 ** (np.arange(start = len(df.columns), stop = 0, step = -1)-1) * df).sum(axis =1)
     ...: 
81.5 ms ± 432 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)