Question: I have a pandas Dataframe of dimensions (`m`,`n`) that is filled with `0` and `1`. 
If each row of the dataframe is considered as a binary number, I would like to generate a pandas Series with the integer number in base 10 represented by that row.

Given the following matrix of dimensions (`m`,`n`) filled with `0` and `1`:

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

```

The method I use right now is this one:

```
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)

```

My issue here is TIMING. If the dataframe has length on the order of `m=1e3`, then the whole process takes less than one second. However, when I with `m=1e6`, it takes about 22 seconds, and I need to run many of these, so I really want to speed it up.

I am aware that the steps slowing down the process are those involving conversion of the `DataFrame` to `str`, i.e. these lines: 

```
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)

```

Does anyone know a more efficient way to create the series of integers in decimal base?? Thanks a lot!

Answer: 
You can use [`dot`](https://docs.scipy.org/doc/numpy/reference/generated/numpy.dot.html) product with bitwise left-shift operator:

```
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)

```
I think this does what you want:

```
(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

```

Explanation:

We want to multiply each column of the dataframe by 2\*\*x, where x is the index of how far it is from the right hand side:

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

array([16,  8,  4,  2,  1], dtype=int32)

```

Once we have this, we multiply the dataframe by it, and sum on axis = 1 to get our series.

Timing:

Your answer:

```
%%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

```

This one:

```
%%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

```

Edit: As @jezrael answers below, a mul and sum is a dot product:

```
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

```