Python 如何一次对数据中的所有列进行分类?(使所有值变为高、中、低)

Python 如何一次对数据中的所有列进行分类?(使所有值变为高、中、低),python,pandas,dataframe,categorical-data,Python,Pandas,Dataframe,Categorical Data,我试图将数据集中的所有值转换为分类值,我希望所有数值根据其分位数值分类为低、平均或高 因此,如果该值低于该系列的25%,则将其转换为“低” 我尝试使用assign,然后应用了我提供的函数: def turn_into_categorical(row): quantile_level = [.25, .5, .75] for r in row: cut = refugees_T_F_V_P_full_data.r.quantile(quantile_level)

我试图将数据集中的所有值转换为分类值,我希望所有数值根据其分位数值分类为低、平均或高

因此,如果该值低于该系列的25%,则将其转换为“低”

我尝试使用assign,然后应用了我提供的函数:

def turn_into_categorical(row):
    quantile_level = [.25, .5, .75]
    for r in row:
        cut = refugees_T_F_V_P_full_data.r.quantile(quantile_level)
        if r >= cut[.75]:
            return "High"
        elif r >= cut[.25] and r < cut[0.75]:
            return "Average"
        else:
            return "Low"

refugees_T_F_V_P_full_data.apply(turn_into_categorical, axis = 1)

预期成果:(举例)


一个想法是使用
pd.DataFrame.quantile
pd.Series.cut

cats = ['Low', 'Medium', 'High']
quantiles = df.iloc[:, 2:].quantile([0, 0.25, 0.75, 1.0])

for col in df.iloc[:, 2:]:
    bin_edges = quantiles[col]
    # special case situations where all values are equal
    if bin_edges.nunique() == 1:
        df[col] = 'Low'
    else:
        df[col] = pd.cut(df[col], bins=bin_edges, labels=cats, include_lowest=True)
结果:

print(df)

    Year  Month CentralEquatoria EasternEquatoria Gogrial Jonglei
0   2014     10           Medium              Low     Low     Low
1   2014     11              Low           Medium     Low    High
2   2014     12              Low           Medium     Low    High
3   2015      1           Medium           Medium     Low     Low
4   2015      2           Medium           Medium     Low    High
5   2015      3           Medium           Medium     Low  Medium
6   2015      4              Low              Low     Low  Medium
7   2015      5           Medium              Low     Low  Medium
8   2015      6              Low              Low     Low  Medium
9   2015      7             High           Medium     Low  Medium
10  2015      8             High             High     Low  Medium
11  2015      9             High              Low     Low  Medium
12  2015     10             High              Low     Low     Low
13  2015     11           Medium           Medium     Low    High
14  2015     12           Medium             High     Low     Low
看起来像你想要的,这正是你想要的。从文档中:

基于分位数的离散化函数

因此,您可以沿着数据帧的列
pd.qcut
Central Equatoria
开始,指定要使用
q=[0,0.25,0.75,1.0]来存储序列的分位数。

df.loc[:,'Central Equatoria':].apply(lambda x: pd.qcut(x, q=[0, 0.25, 0.75, 1.0], 
                                    labels =['low','medium','high']) 
                                    if not x.nunique() == 1 else 'low'))
输出

使用
pd.cut()
df.apply()


最终使用最古老的方式:

new_df = pd.DataFrame()
name_list = list(df)

for name in name_list:
    if name != 'Year' and name != 'Month':
        new_row = []
        quantiles = df[name].quantile([.25, .5, .75])
        row_list = df[name].tolist()
        for i, value in enumerate(row_list):
            if value < quantiles[.25]:
                new_row.append("Low")
            elif value < quantiles[.75] and value >= quantiles[.25]:
                new_row.append("Average")
            else:
                new_row.append("High")
        series = pd.Series(new_row)
        new_df[name] = series.values

new_df.head()
new_df=pd.DataFrame()
名称\列表=列表(df)
对于名称列表中的名称:
如果名称!='年份和名称!='月份:
新_行=[]
分位数=df[name]。分位数([.25、.5、.75])
行列表=df[name].tolist()
对于i,枚举中的值(行列表):
如果值<分位数[.25]:
新增行。追加(“低”)
elif值<分位数[.75]和值>=分位数[.25]:
新增行。追加(“平均值”)
其他:
新增行。追加(“高”)
系列=局部放电系列(新行)
new_df[name]=series.values
新(财务总监)

作为评论,这是一个写得很好的问题,有一个有趣的问题-谢谢!如果OP愿意使用int标签而不是字符串,我想我们可以将其矢量化。我只是想敲定一个idea@roganjosh,
pd.cut
我相信它是完全矢量化的,最后的“字符串”系列实际上是有效的分类,即由整数数组支持。啊,噗,我看到了
for
循环,并以错误的方式读了它!我要的是
np.digitalize
。您说得对。我已经尝试了该代码,但它返回的错误与我尝试@yatu的代码
ValueError:Bin边必须是唯一的:数组([0,0,5,26])。您可以通过设置“duplicates”(重复)kwarg来删除重复边
比我的解决方案更好:)。。基本上,这结合了
分位数
切割
方法。是的,它直接使用分位数信息进行分类。谢谢:)我试图实现您的代码和@jpp的代码,但是pd.qcut函数似乎总是返回错误
ValueError:(“Bin边必须是唯一的:数组([0,0,2,7])。\n您可以通过设置“duplicates”kwarg来删除重复边,“发生在北加扎勒河的索引中”)
我试图从这里搜索解决方案,并添加了一个参数
duplicates='drop'
,但它仍然返回
ValueError:(“垃圾箱标签必须比垃圾箱边缘的数量少一个”,“发生在北加扎勒河的索引中”)
完整的代码在这里
难民数据。iloc[:,2:。应用(lambda x:pd.qcut(x,duplicates='drop',q=[0,0.25,0.75,1.0],标签=['low','medium','high'])如果不是x.nunique()==1,则为'low'
df.loc[:,'Central Equatoria':].apply(lambda x: pd.qcut(x, q=[0, 0.25, 0.75, 1.0], 
                                    labels =['low','medium','high']) 
                                    if not x.nunique() == 1 else 'low'))
       Central Equatoria Eastern Equatoria Gogrial Jonglei
0            medium              low     low     low
1               low           medium     low    high
2               low           medium     low    high
3            medium           medium     low     low
4            medium           medium     low    high
5            medium           medium     low  medium
6               low              low     low  medium
7            medium              low     low  medium
8               low              low     low  medium
9              high           medium     low  medium
10             high             high     low  medium
11             high              low     low  medium
12             high              low     low     low
13           medium           medium     low    high
14           medium             high     low     low
df.iloc[:,2:]=df.iloc[:,2:].apply(lambda x:pd.cut(x, 3, labels=['Low','Med','High']), axis=1)

    Year    Month   Central_Equatoria   Eastern_Equatoria   Gogrial Jonglei
0   2014    10      High    Low         Low                 Med
1   2014    11      Low     Low         Low                 High
2   2014    12      Low     Med         Low                 High
3   2015    1       High    Low         Low                 Med
4   2015    2       Med     Med         Low                 High
5   2015    3       High    Med         Low                 High
new_df = pd.DataFrame()
name_list = list(df)

for name in name_list:
    if name != 'Year' and name != 'Month':
        new_row = []
        quantiles = df[name].quantile([.25, .5, .75])
        row_list = df[name].tolist()
        for i, value in enumerate(row_list):
            if value < quantiles[.25]:
                new_row.append("Low")
            elif value < quantiles[.75] and value >= quantiles[.25]:
                new_row.append("Average")
            else:
                new_row.append("High")
        series = pd.Series(new_row)
        new_df[name] = series.values

new_df.head()