Python 根据列名的一部分对 Dataframe 列进行分类

Python Categorizing Dataframe columns based on part of the colomn name

可重现数据:

import random
    data = {'test_1_a':random.sample(range(1, 50), 7),
            'test_1_b':random.sample(range(1, 50), 7),
    'test_1_c':random.sample(range(1, 50), 7),
    'test_2_a':random.sample(range(1, 50), 7),
    'test_2_b':random.sample(range(1, 50), 7),
    'test_2_c':random.sample(range(1, 50), 7),
    'test_3_a':random.sample(range(1, 50), 7),
    'test_4_b':random.sample(range(1, 50), 7),
    'test_4_c':random.sample(range(1, 50), 7)}
    df = pd.DataFrame(data)

描述:

我有一个类似于我上面给出的示例的数据框,其中包含 1000 列左右。列名格式如下:

test_number_family 所以 test_1_c 将是数字类型 1 和“c”的族

我想按相同“系列”类型的列名对 df 进行分类。所以我的最终输出需要是相同系列值列表的列表:

输出示例:

[[a_familily 个值],[b_familily 个值],...]

它也看起来像列的值:

[ [test_1_a, test_2_a , test_3_a ] , [test_1_b, test_2_b , test_3_b ] , ...]

我有:

#### transfers data frame into a sorted dict (by column name) by columns as key
col_names = [ i for (i,j) in df.iteritems() ]
col_vals = [ j for (i,j) in df.iteritems() ]

df_dict = dict(zip(col_names, col_vals))


families = np.unique([ i.split("_")[2] for i in dict1.keys() ])

我已将每个列名称及其关联值分类,并提取了我希望在最终输出中作为“家庭”拥有的唯一组数。我现在正在寻求帮助,将数据框分类为与我上面给出的输出示例相同的长度(系列)数量的列表。

希望我的解释很清楚,感谢您抽出宝贵的时间!

让我们跟踪字典中的不同族,键是字母(族),值是包含某个族的列的列表。

因为我们知道每一列都以与其家族相关的字母结尾,所以我们可以将其用作字典中的键。

from collections import defaultdict
families = defaultdict(list)

for col in df.columns:
    families[col[-1]].append(df[col])

现在例如,在families["a"]中,我们有:

[0    26
 1    13
 2    11
 3    35
 4    43
 5    45
 6    46
 Name: test_1_a, dtype: int64,
 0    10
 1    15
 2    20
 3    43
 4    40
 5    35
 6    22
 Name: test_2_a, dtype: int64,
 0    35
 1    48
 2    38
 3    13
 4     3
 5    10
 6    25
 Name: test_3_a, dtype: int64]

我们可以使用 concat.

轻松获得 per-family 数据框
df_a = pd.concat(families["a"], axis=1)

得到我们:

   test_1_a  test_2_a  test_3_a
0        26        10        35
1        13        15        48
2        11        20        38
3        35        43        13
4        43        40         3
5        45        35        10
6        46        22        25

如果我们要为每个家庭创建一个数据框字典,

dfs = {f"df_{fam}" : pd.concat(families[fam], axis=1) for fam in families.keys()}

现在,字典 dfs 包含:

{'df_a':    test_1_a  test_2_a  test_3_a
 0        26        10        35
 1        13        15        48
 2        11        20        38
 3        35        43        13
 4        43        40         3
 5        45        35        10
 6        46        22        25,
 'df_b':    test_1_b  test_2_b  test_4_b
 0        18         4        44
 1        48        43         2
 2        30        21         4
 3        46        12        16
 4        42        14        25
 5        22        24        13
 6        43        40        43,
 'df_c':    test_1_c  test_2_c  test_4_c
 0        25        15         5
 1        36        39        28
 2         6         3        37
 3        22        48        16
 4         2        34        25
 5        39        16        30
 6        32        36         2}

您如何看待这样的方法?将 pd.wide_to_long 与带有拆分列的长数据帧的结果一起使用,一个包含整个 classification,如 1_a,一个仅包含数字,一个包含家庭及其值。

df = (pd.wide_to_long(
    df.reset_index(),stubnames='test_',i='index',j='classification',suffix='\d_\w')
      .reset_index()
      .drop('index',axis=1)
      .rename(columns={'test_':'values'}))

df[['number', 'family']] = df['classification'].str.split('_', expand=True)
df = df.reindex(columns=['classification', 'number', 'family', 'values'])

print(df)

   classification number family  values
0             1_a      1      a      29
1             1_a      1      a      46
2             1_a      1      a       2
3             1_a      1      a       6
4             1_a      1      a      16
..            ...    ...    ...     ...
58            4_c      4      c      30
59            4_c      4      c      23
60            4_c      4      c      26
61            4_c      4      c      40
62            4_c      4      c      39

易于分组或过滤以进行更多分析。 如果你想获得 dictslists 的特定数据,这里有一些例子:

filter1 = df.loc[df['classification']=='1_a',:]
filter2 = df.loc[df['number']=='2','values']

filter1.to_dict(orient='list')
Output: 
{'classification': ['1_a', '1_a', '1_a', '1_a', '1_a', '1_a', '1_a'],
 'number': ['1', '1', '1', '1', '1', '1', '1'],
 'family': ['a', 'a', 'a', 'a', 'a', 'a', 'a'],
 'values': [29, 46, 2, 6, 16, 12, 38]}

filter2.tolist()
Output: 
[8, 2, 43, 9, 5, 30, 28, 26, 25, 49, 3, 1, 47, 44, 16, 9, 8, 15, 24, 36, 1]

不确定我是否完全理解问题;这是你的想法吗:

dict(list(df.groupby(df.columns.str[-1], axis = 1)))

{'a':    test_1_a  test_2_a  test_3_a
 0        20        36        14
 1         4         7        16
 2        28        13        28
 3         3        40         9
 4        38        41         5
 5        34        47        18
 6        49        25        46,
 'b':    test_1_b  test_2_b  test_4_b
 0        35        10        44
 1        46        14        23
 2        26        11        36
 3        17        27         4
 4        13        16        42
 5        20        38         9
 6        41        22        18,
 'c':    test_1_c  test_2_c  test_4_c
 0        22         2        26
 1        42        24         3
 2        15        16        41
 3         7        11        16
 4        40        37        47
 5        38         7        33
 6        39        22        24}

这会根据列名中的最后一个字母对列进行分组。

如果这不是您想要的,请发表评论,也许可以更好地解释一下我误解了您的意图的地方。