pandas 系列位到十进制整数
pandas series bits to integer in decimal base
我有一个 pandas 维度(m
,n
)的数据框,其中填充了 0
和 1
。
如果数据帧的每一行都被认为是一个二进制数,我想生成一个 pandas 系列,其中以 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
,则整个过程不到一秒。但是,当我使用 m=1e6
时,大约需要 22 秒,而且我需要 运行 很多,所以我真的想加快速度。
我知道减慢进程的步骤涉及将 DataFrame
转换为 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)
一旦我们有了这个,我们就将数据帧乘以它,然后在 axis = 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
您正确地将字符串转换识别为瓶颈。这些可以通过将二进制转换为十进制的教科书方法来避免。将每一列乘以相应的值,然后对每一行求和。在过时的安装中,这会产生约 380 倍的加速。下面的代码片段对 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
您可以将 dot
乘积与按位左移运算符一起使用:
a = df.values
b = a.dot(1 << np.arange(a.shape[-1] - 1, -1, -1))
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)
我有一个 pandas 维度(m
,n
)的数据框,其中填充了 0
和 1
。
如果数据帧的每一行都被认为是一个二进制数,我想生成一个 pandas 系列,其中以 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
,则整个过程不到一秒。但是,当我使用 m=1e6
时,大约需要 22 秒,而且我需要 运行 很多,所以我真的想加快速度。
我知道减慢进程的步骤涉及将 DataFrame
转换为 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)
一旦我们有了这个,我们就将数据帧乘以它,然后在 axis = 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
您正确地将字符串转换识别为瓶颈。这些可以通过将二进制转换为十进制的教科书方法来避免。将每一列乘以相应的值,然后对每一行求和。在过时的安装中,这会产生约 380 倍的加速。下面的代码片段对 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
您可以将 dot
乘积与按位左移运算符一起使用:
a = df.values
b = a.dot(1 << np.arange(a.shape[-1] - 1, -1, -1))
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)