我有一个简单的问题。我有一个包含两列的数据框df
。对于在这两列中出现的每个字符串,我想计算在任一列中都有符号的行数。
E.g。
g k
a h
c i
j e
d i
i h
b b
d d
i a
d h
以下代码有效但效率很低。
for elem in set(df.values.flat):
print elem, len(df.loc[(df[0] == elem) | (df[1] == elem)])
a 2
c 1
b 1
e 1
d 3
g 1
i 4
h 3
k 1
j 1
然而,这是非常低效的,我的数据帧很大。效率低下来自于分别为df中的每个不同符号调用df.loc[(df[0] == elem) | (df[1] == elem)]
。
有这么快的方法吗?
答案 0 :(得分:2)
您可以使用loc
过滤掉'col2'
的行级匹配,将已过滤的'col2'
值附加到'col1'
,然后调用value_counts
:< / p>
counts = df['col1'].append(df.loc[df['col1'] != df['col2'], 'col2']).value_counts()
结果输出:
i 4
d 3
h 3
a 2
j 1
k 1
c 1
g 1
b 1
e 1
注意:如果您希望输出按字母顺序显示,可以将.sort_index()
添加到计数代码的末尾。
<强>计时强>
使用以下设置生成更大的样本数据集:
from string import ascii_lowercase
n = 10**5
data = np.random.choice(list(ascii_lowercase), size=(n,2))
df = pd.DataFrame(data, columns=['col1', 'col2'])
def edchum(df):
vals = np.unique(df.values)
count = np.maximum(df['col1'].str.get_dummies().reindex_axis(vals, axis=1).fillna(0), df['col2'].str.get_dummies().reindex_axis(vals, axis=1).fillna(0)).sum()
return count
我得到以下时间:
%timeit df['col1'].append(df.loc[df['col1'] != df['col2'], 'col2']).value_counts()
10 loops, best of 3: 19.7 ms per loop
%timeit edchum(df)
1 loop, best of 3: 3.81 s per loop
答案 1 :(得分:1)
好吧这比我想象的要复杂得多,不确定这会如何扩展,但是如果你有很多重复值,那么它会比你当前的方法更有效,基本上我们可以使用str.get_dummies
并重新索引结果中的列为所有唯一值生成dummies df,然后我们可以在2 dfs和np.maximal
上使用sum
:
In [77]:
t="""col1 col2
g k
a h
c i
j e
d i
i h
b b
d d
i a
d h"""
df = pd.read_csv(io.StringIO(t), delim_whitespace=True)
np.maximum(df['col1'].str.get_dummies().reindex_axis(vals, axis=1).fillna(0), df['col2'].str.get_dummies().reindex_axis(vals, axis=1).fillna(0)).sum()
Out[77]:
a 2
b 1
c 1
d 3
e 1
g 1
h 3
i 4
j 1
k 1
dtype: float64
这里的vals只是唯一的值:
In [80]:
vals = np.unique(df.values)
vals
Out[80]:
array(['a', 'b', 'c', 'd', 'e', 'g', 'h', 'i', 'j', 'k'], dtype=object)