我的数据采用以下格式:
index keys
1 key 1
2 key 1\nkey 2\nkey 3
3 key 2\nkey 4\nkey 5
5 key 2\nkey 3\nkey 5
我感兴趣的关键字位于键列中,以\n
分隔。我想将每个密钥转换为列名称,并使用True
或1
标记来自其所在位置的行,如下所示:
index key 1 key 2 key 3 key 4 key 5
1 1 0 0 0 0
2 1 1 1 0 0
3 0 1 0 1 1
5 0 1 1 0 1
现在,我做的是迭代索引,将每行的键列表保存到字典中,然后使用pandas.DataFrame.from_dict
转换重新导入它,如下所示:
l=[]
for i in df.index:
d={j:True for j in df["keys"][i].split("\n")}
l.append(d)
new_df=pandas.DataFrame(l)
它非常快,但由于有很多NaN
,因此在将数据帧转换为int64
类型之前,数据帧的内存消耗量非常大。然而,我有几十万行。有没有人知道一种更有效的方法,如果可能的话,可以避免自己迭代行?
答案 0 :(得分:3)
这是理解的一种方式
In [5442]: pd.DataFrame([{k:1 for k in x.split('\\n')} for x in df['keys']]).fillna(0)
Out[5442]:
key 1 key 2 key 3 key 4 key 5
0 1.0 0.0 0.0 0.0 0.0
1 1.0 1.0 1.0 0.0 0.0
2 0.0 1.0 0.0 1.0 1.0
3 0.0 1.0 1.0 0.0 1.0
使用apply
的另一种方式,在较大的数据上会慢一些
In [5429]: df['keys'].apply(lambda x: pd.Series({k:1 for k in x.split('\\n')})
).fillna(0).astype(int)
Out[5429]:
key 1 key 2 key 3 key 4 key 5
0 1 0 0 0 0
1 1 1 1 0 0
2 0 1 0 1 1
3 0 1 1 0 1
计时
In [5447]: dff.shape
Out[5447]: (20000, 2)
In [5444]: %timeit pd.DataFrame([{k: 1for k in x.split('\\n')} for x in dff['keys']]).fillna(0)
10 loops, best of 3: 59.6 ms per loop
In [5445]: %timeit dff['keys'].str.split(r'\\n', expand=True).stack().str.get_dummies().groupby(level=0).sum()
1 loop, best of 3: 399 ms per loop
In [5446]: %%timeit
...: d = pd.get_dummies(dff['keys'].str.split(r'\\n', expand=True))
...: d.groupby(d.columns.str.split('_').str[1], axis=1).sum()
1 loop, best of 3: 62.0 ms per loop
答案 1 :(得分:2)
选项1
str.split
+ stack
+ str.get_dummies
+ groupby
+ sum
:
df
keys
index
1 key 1
2 key 1\nkey 2\nkey 3
3 key 2\nkey 4\nkey 5
5 key 2\nkey 3\nkey 5
df['keys'].str.split('\n', expand=True).stack()\
.str.get_dummies().groupby(level=0).sum()
key 1 key 2 key 3 key 4 key 5
index
1 1 0 0 0 0
2 1 1 1 0 0
3 0 1 0 1 1
5 0 1 1 0 1
选项2
使用pd.get_dummies
,绕过stack
:
d = pd.get_dummies(df['keys'].str.split('\n', expand=True))
d.groupby(d.columns.str.split('_').str[1], axis=1).sum()
key 1 key 2 key 3 key 4 key 5
index
1 1 0 0 0 0
2 1 1 1 0 0
3 0 1 0 1 1
5 0 1 1 0 1
选项3
使用stack
+ value_counts
+ unstack
:
df['keys'].str.split('\n', expand=True).stack()\
.groupby(level=0).value_counts().unstack().fillna(0)
key 1 key 2 key 3 key 4 key 5
index
1 1.0 0.0 0.0 0.0 0.0
2 1.0 1.0 1.0 0.0 0.0
3 0.0 1.0 0.0 1.0 1.0
5 0.0 1.0 1.0 0.0 1.0