我有一个由几个列组成的Pandas数据帧,其中的单元格可能包含也可能不包含字符串。举个例子:
import numpy as np
import pandas as pd
df = pd.DataFrame({'A':['asfe','eseg','eesg','4dsf','','hdt','gase','gex','gsges','hhbr'],
'B':['','bdb','htsdg','','rdshg','th','tjf','','',''],
'C':['hrd','jyf','sef','hdsr','','','','','hdts','aseg'],
'D':['','','hdts','afse','nfd','','htf','','',''],
'E':['','','','','jftd','','','','jfdt','']})
...看起来像:
A B C D E
0 asfe hrd
1 eseg bdb jyf
2 eesg htsdg sef hdts
3 4dsf hdsr afse
4 rdshg nfd jftd
5 hdt th
6 gase tjf htf
7 gex
8 gsges hdts jfdt
9 hhbr aseg
我想创建一个包含列是否包含字符串的二进制表示的列;例如,第一行将表示为10100。
我能想到这样做的唯一方法是:
这是我创建的代码:
scratchdf = pd.DataFrame().reindex_like(df)
for col in df.columns.values:
scratchdf[col] = df[col].str.contains(r'\w+',regex = True).astype(int)
scratchdf['bin'] = scratchdf['A'].astype(str) + \
scratchdf['B'].astype(str) + \
scratchdf['C'].astype(str) + \
scratchdf['D'].astype(str) + \
scratchdf['E'].astype(str)
df = df.join(scratchdf['bin'])
...产生最终的数据帧:
A B C D E bin
0 asfe hrd 10100
1 eseg bdb jyf 11100
2 eesg htsdg sef hdts 11110
3 4dsf hdsr afse 10110
4 rdshg nfd jftd 01011
5 hdt th 11000
6 gase tjf htf 11010
7 gex 10000
8 gsges hdts jfdt 10101
9 hhbr aseg 10100
这可行,但似乎有点浪费(特别是对于大型数据帧)。有没有办法直接创建二进制表示列,而无需创建临时数据帧?
答案 0 :(得分:1)
方法1
a = np.where(df != "", "1", "0").astype("|S1")
df["bin"] = np.apply_along_axis(lambda x: x.tostring().decode("utf-8"), 1, a)
方法2
df["bin"] = np.append(
np.where(df != "", "1", "0").astype("S1"),
np.array([["\n"]]).astype("S1").repeat(df.shape[0], axis=0),
axis=1
).tostring().decode("utf-8")[:-1].split("\n")
方法2将\n
附加到numpy数组的末尾
array([[b'1', b'0', b'1', b'0', b'0', b'\n'],
[b'1', b'1', b'1', b'0', b'0', b'\n'],
[b'1', b'1', b'1', b'1', b'0', b'\n'],
...,
[b'1', b'0', b'0', b'0', b'0', b'\n'],
[b'1', b'0', b'1', b'0', b'1', b'\n'],
[b'1', b'0', b'1', b'0', b'0', b'\n']], dtype='|S1')
然后拨打tostring
和decode
。删除最后一个“\ n”,然后按“\ n”拆分。
方法3 (使用view
参考:numpy array of chars to string)
np.ascontiguousarray(
np.where(df != "", "1", "0").astype("S1")
).view('|S5').astype(str)
(Based on jezrael's setup df = pd.concat([df] * 1000, ignore_index=True))
# method 2
%timeit np.append(np.where(df != "", "1", "0").astype("S1"), np.array([["\n"]]).astype("S1").repeat(df.shape[0], axis=0), axis=1).tostring().decode("utf-8")[:-1].split("\n")
12.3 ms ± 175 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# method 3
%timeit np.ascontiguousarray(np.where(df != "", "1", "0").astype("S1")).view('|S5').astype(str)
12.8 ms ± 164 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# method 1 (slower)
%timeit np.apply_along_axis(lambda x: x.tostring().decode("utf-8"), 1, np.where(df != "", "1", "0").astype("S1"))
45 ms ± 1.86 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
jezrael的复制实验。
In [99]: %timeit df.astype(bool).astype(int).astype(str).values.sum(axis=1)
28.9 ms ± 782 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [100]: %timeit (df != '').astype(int).astype(str).values.sum(axis=1)
29 ms ± 645 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [101]: %timeit (df != '').astype(int).astype(str).apply(''.join, axis=1)
168 ms ± 2.93 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [102]: %timeit df.astype(bool).astype(int).astype(str).apply(''.join, axis=1)
173 ms ± 7.36 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [103]: %timeit df.astype(bool).astype(int).apply(lambda row: ''.join(str(i) for i in row), axis=1)
159 ms ± 3.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)