我有一个熊猫数据帧df,如下所示。在问题的末尾给出了df.to_dict()。
Values
0 0.010545
1 0.018079
2 0.019491
3 0.042556
4 0.062404
5 0.077826
6 0.080170
7 0.085732
8 0.097538
9 0.104020
10 0.116825
11 0.121143
12 0.147592
13 0.147939
14 0.154998
15 0.157179
16 0.185593
17 0.200474因为我有18个值,我想把它们分成3个不同的框,分别是“低”、“中”和“高”。我还想知道每个垃圾桶的门槛是多少。
我做到了
df.apply(lambda x:pd.cut(x, bins = 3, labels=['low','medium','high']), axis = 0)并得到了以下内容。
Values
0 low
1 low
2 low
3 low
4 low
5 medium
6 medium
7 medium
8 medium
9 medium
10 medium
11 medium
12 high
13 high
14 high
15 high
16 high
17 high我得到了5个低值,7个中值和6个高值。我很好奇,既然我有18个可以被3整除的值,为什么我没有得到低,中,高每个值的6个值。
我还尝试计算了33和67个百分位数。df.quantile(0.33)给了我0.079256,df.quantile(0.67)给了我0.131458。
我意识到,对于我应用的函数,这不是低-中或中-高的确切阈值。因为索引5中的值是0.077826,低于33个百分位数(0.079256),但被归类为“中等”。
我计算百分位数的方法正确吗?绑定是否也以相同的方式应用阈值?当我应用上面的pd.cut(bins = 3,...)函数时,如何获得低-中和中-高的阈值?
是否可以基于0,0.33,0.67,1作为百分位数将数据集分为相等数量的低,中和高?最初,我认为我的函数做了同样的事情,但它看起来不是这样的。
df.to_dict()如下所示:
{'Values': {0: 0.0105451195503243,
1: 0.01807949818715662,
2: 0.01949062427056047,
3: 0.04255627128922379,
4: 0.06240376897660298,
5: 0.07782590379116708,
6: 0.0801695217422988,
7: 0.0857317068170362,
8: 0.0975380806573516,
9: 0.1040201601240209,
10: 0.1168250536954563,
11: 0.1211426350058809,
12: 0.1475922708843568,
13: 0.1479393893305906,
14: 0.1549975110559438,
15: 0.157178926862648,
16: 0.1855926516856752,
17: 0.2004743800065415}}发布于 2021-10-19 11:29:30
引用pd.cut的文档,在bin参数的描述下:
int :定义x...范围内的等宽箱数...
这意味着在您的例子中,序列的范围(即最大值减最小值)被分成3个长度相等的段(在本例中为0.06331)。所以你不能保证得到相同大小的垃圾桶。
例如
df = pd.DataFrame([1, 2, 3, 4, 5, 100])
df.apply(lambda x:pd.cut(x, bins = 3, labels=['low','medium','high']), axis = 0)将会返回
0 low
1 low
2 low
3 low
4 low
5 high因为bin边缘是33和66 (实际值实际上略有不同,因为pandas稍微扩展了范围,以包括数组的最小值和最大值)。
要回答你的问题,你可以做的一件事是对数组进行排序,并将其分成3部分。实现这一目标的代码示例如下:
# Sort array and keep track of old indexes to get back the original sorting at the end
df = df.sort_values('Values').reset_index()
# Split df into 3 chunks
chunk_size = len(df) // 3
for i, bin_label in zip(range(0, len(df), chunk_size), range(3)):
df.loc[i: i + chunk_size, 'bin'] = bin_label
# Assign eventual remaining rows to last bin
df['bin'] = df['bin'].fillna(method='ffill')
# Go back to the original sorting
df = df.set_index('index').sort_index()我考虑了数组不一定排序的情况。如果您的数组已经像示例中那样进行了排序,那么您可以这样做
# Split df into 3 chunks
chunk_size = len(df) // 3
for i, bin_label in zip(range(0, len(df), chunk_size), range(3)):
df.loc[i: i + chunk_size, 'bin'] = bin_label
# Assign eventual remaining rows to last bin
df['bin'] = df['bin'].fillna(method='ffill')在此之后,您可以根据需要重命名存储箱,或者可以将for循环行中的range(3)替换为类似于['low', 'medium', 'high']的列表。
发布于 2021-10-19 12:15:50
我发现df.apply(lambda x:pd.qcut(x, q = [0, 0.33, 0.67, 1], labels=['low','medium','high']), axis = 0)给我的分类是从0到33个百分位数,从33个百分位数到67个百分位数,直到1。
但有时,如果存在非唯一的二进制边缘,则它不起作用。例如,如果我有1,1,1,1,2,3,4,33个百分位数是1,67个百分位数是1.69。但我不能根据33和67个百分位数作为阈值来平均划分数据。
我还弄清楚了pd.cut(x, bins = n)取什么作为阈值。据我所知,如果n= 3,它会尝试用range/n来打破我的数据。中低阈值是(min + range/n)。例如,在1,1,1,1,1,2,3,4中。中低阈值为1+(4-1)/3 = 1+1 = 2。但2仍处于低阈值。任何大于2的值都是中等。
同样,中-高阈值是max - (range/n)。在上面的数据中,它是4- 3/3 = 4-1 = 3。但3仍然是中等的,任何高于3的值都被归类为高。
https://stackoverflow.com/questions/69629555
复制相似问题