我想比较所有行中的特定列,或者所有行中70%的列,如果它们是唯一的,则将该值提取为0,否则将其提取到新列中。
如果示例数据框如下:
A B C D E F G H I J K L
32145 Basket 2 2 2 2 2 2 2 2 2 2
43290 Red ball 1 1 0 0 1 1 1 1 1 1
32891 wht ball 4 4 4 0 4 0 4 0 4 4
45328 grn ball 1 1 1 1 1 1 2 1 1 1
34531 blk ball 6 6 6 6 0 0 0 0 6 0
结果应如下:
A B C D E F G H I J K L M
32145 Basket 2 2 2 2 2 2 2 2 2 2 2 (100% of rows are similar)
43290 Red ball 1 1 0 0 1 1 1 1 1 1 1 (80% of rows are similar)
32891 wht ball 4 4 4 0 4 0 4 0 4 4 4 (70% of rows are similar)
45328 grn ball 1 1 1 1 1 1 2 1 1 1 1 (90% of rows are similar)
34531 blk ball 6 6 6 6 0 0 0 0 6 0 0 (only 50% of rows are similar)
我使用以下答案来查找100%相似的行。
compare multiple specific columns of all rows
我想查找是否所有行中至少有70%相似,否则为0。
行数的考虑因素可能会有所变化,因为它并非一直都是恒定的。
我想要结果行中的唯一值(仅当且超过70%的行相似时),否则为0。(来自上面的示例“ M”列)
很高兴知道一些建议。
答案 0 :(得分:3)
您可以通过scipy.stats.mode
逐行计算模式,然后采用均值。本示例通过pd.Series.mask
显式忽略0
值。如果允许,不包括此蒙版(根据下面的基准测试),将会提高性能。
from scipy import stats
arr = df.iloc[:, 2:]
modes = stats.mode(arr.mask(arr.eq(0)), 1)[0].ravel()
df['ratio'] = arr.eq(modes, axis=0).mean(1)
print(df)
A B C D E F G H I J K L ratio
0 32145 Basket 2 2 2 2 2 2 2 2 2 2 1.0
1 43290 Red ball 1 1 0 0 1 1 1 1 1 1 0.8
2 32891 wht ball 4 4 4 0 4 0 4 0 4 4 0.7
3 45328 grn ball 1 1 1 1 1 1 2 1 1 1 0.9
4 34531 blk ball 6 6 6 6 0 0 0 0 6 0 0.5
对于大量的行与列,并使用类似算法,scipy.stats.mode
的表现优于collections.Counter
:
from scipy.stats import mode
from collections import Counter
def counter_ratio(df):
n= float(len(df.iloc[:, 2:].columns.values))
df['ratio']=df.iloc[:, 2:].apply(lambda x: Counter(x.values).most_common(1)[0][1]/n,axis=1)
return df
def mode_ratio(df):
arr = df.iloc[:, 2:].values
df['ratio'] = np.mean(arr == mode(arr, 1)[0], axis=1)
return df
n = 10**4
df = pd.concat([df]*n, ignore_index=True)
%timeit counter_ratio(df.copy()) # 1.88 s per loop
%timeit mode_ratio(df.copy()) # 32.7 ms per loop
答案 1 :(得分:1)
尝试一下
n= float(len(df.iloc[:, 2:].columns.values))
df['ratio']=df.iloc[:, 2:].apply(lambda x: collections.Counter(x.values).most_common(1)[0][1]/n,axis=1)
输出:
A B C D E F G H I J I.1 K ratio
0 32145 Basket 2 2 2 2 2 2 2 2 2 2 1.0
1 43290 Red ball 1 1 0 0 1 1 1 1 1 1 0.8
2 32891 wht ball 4 4 4 0 4 0 4 0 4 4 0.7
3 45328 grn ball 1 1 1 1 1 1 2 1 1 1 0.9
4 34531 blk ball 6 6 6 6 0 0 0 0 6 0 0.5
效果指标:
df=(pd.concat([df]*10000,ignore_index=True))
我的建议解决方案:
start = time.time()
n= float(len(df.iloc[:, 2:].columns.values))
df['ratio']=df.iloc[:, 2:].apply(lambda x: collections.Counter(x.values).most_common(1)[0][1]/n,axis=1)
end = time.time()
print(end - start)
O/P: 0.7386555671691895
@jpp的解决方案:
start = time.time()
arr = df.iloc[:, 2:]
modes = stats.mode(arr.mask(arr.eq(0)), 1)[0].ravel()
df['ratio'] = arr.eq(modes, axis=0).mean(1)
end = time.time()
print(end - start)
O/P: 1.281557559967041
@Sandeep Kadapa的解决方案:
start = time.time()
d = (df.iloc[:, 2:].apply(pd.value_counts, 1).drop(0, 1).max(1)/df.iloc[:, 2:].shape[1])
df['L'] = np.where(d>0.5, df.iloc[:, 2:].max(1), 0)
end = time.time()
print(end - start)
O/P: 73.34089946746826