首先,谢谢你的帮助
我有大型pandas DataFrame,我需要为每列快速“排名”转换:
1]如果列只有0-1,则什么都不做
2]其他(对于每一栏):
a]在列
中查找唯一值b]对它们进行排序
c]对于列的每个元素,将其值替换为sort-unique“排名”列表中的位置
可选的:
d]将这个新值转换为区间[-0.99,0.99]
e]将scipy.special.erfinv应用于每个元素(以获得“正常”的分布)
如果需要关注速度,我怎么能和熊猫一起做这件事呢。
感谢名单
答案 0 :(得分:4)
获取仅包含0
或1
:
columns_to_handle = (~df.isin([0,1])).any()
将列类型转换为分类可以方便地处理步骤a,b和c:
df.some_column.astype('category').cat.codes
不幸的是,这似乎需要在列上进行循环(通过apply
),但如果您没有太多列,那么这仍然应该相当快。
重新缩放可以通过减去最小值并除以每列的最大值来完成。但是,由于每列的最小值已经为0,因此第一步是多余的。
Scipy的erfinv
可以将数据帧作为输入。但是,值必须介于-1
和1
之间,独占。因此范围将epsilon
更小。
import pandas as pd
from scipy.special import erfinv
df = pd.DataFrame(
[['a', 10, 0],
['b', 11, 1],
['c', 9, 0],
['d', 12, 1]],
columns=['val1', 'val2', 'val3']
)
columns_to_handle = (~df.isin([0, 1])).any()
intermediate = df.loc[:, columns_to_handle].apply(lambda x: x.astype('category').cat.codes)
epsilon = 0.0001
# intermediate -= intermediate.min() # the minimum is 0 for every column already
intermediate /= intermediate.max()/(2-2*epsilon)
intermediate -= (1-epsilon)
intermediate = erfinv(intermediate)
result = pd.concat(
[intermediate,
df.loc[:, ~columns_to_handle]],
axis=1)
result
是以下数据框:
val1 val2 val3
0 -2.751064 -0.304538 0
1 -0.304538 0.304538 1
2 0.304538 -2.751064 0
3 2.751064 2.751064 1