在pandas数据框中自动分组具有相似名称的多个列

时间:2015-08-10 20:48:30

标签: python pandas group-by

我在pandas数据框中有3,100个列。 column_names的示例是

  

[price_of_apple_2006_01,price_of_apple_2006_02,   price_of_apple_2006_03,price_of_apple_2007_01,   price_of_apple_2007_02,price_of_apple_2008_01,   price_of_apple_2008_02,price_of_apple_2008_03,   price_of_apple_2008_04,....,price_of_orange_2006_01,   price_of_orange_2006_02,price_of_orange_2006_03,   price_of_orange_2006_04 ...... price_of_iphone(2006年至2015年   每月),price_of_samsung(2006年至2015年每月),   price_of_mango(2006年至2015年每月).....]

我想自动组合

等列
  

[price_of_apple_2006_01,price_of_apple_2006_02,   price_of_apple_2006_03] price_of_apple_2007_01,   price_of_apple_2007_02,price_of_apple_2008_01,   price_of_apple_2008_02,price_of_apple_2008_03,   price_of_apple_2008_04,   price_of_orange_2006_01,price_of_orange_2006_02,price_of_orange_2006_03,   price_of_orange_2006_04,price_of_orange_2006_05,price_of_orange_2006_06 ......

并将它们转换为

  

price_of_apple_2006,price_of_apple_2007,price_of_apple_2008,   price_of_orange_2006 .....

取平均值(即price_of_apple_2008有5个月,2006年有2个月,2007年有3个月等等(此处没有图案))

要做到这一点,我应该能够做3个步骤:

1)查找相似的列名并将它们分组到一个名称中 2)跟踪每组中有多少相似的列 3)取平均值

  

次要的:

另外,对于少数类型的列有12个月,所以我想将它们转换为季度并分析为此我需要2个步骤 1)我应该能够编写代码来查找12次列名(price_of_orange_2006_01,price_of_orange_2006_02,price_of_orange_2006_03 ....)

2)然后我应该能够平均它们并转换为按季度(price_of_orange_2006_Q1,price_of_orange_2006_Q2,price_of_orange_2006_Q3)

有人可以帮我解决这个问题,手动执行3,100列会花费我很多时间

1 个答案:

答案 0 :(得分:1)

您可以将函数传递给groupby方法,该方法对列名称起作用,如:

grouped = df.groupby(lambda col: col[:-3], axis=1)
average_prices = grouped.mean()
n_months = grouped.size()

按列传递axis=1组。我不确定我指定的功能是否正是您想要的,但是从您展示的示例中,按照名称和年份对组名进行分组,假设名称以_01表示月份的结尾。对于第二部分,您可以使用n_months通过执行以下操作来确定哪些名称 - 年份组合有12个月:

with_full_year = n_months[n_months == 12].index

然后,您可以为原始数据框生成所有列的列表:

cols = [{}_{:0>2d}.format(name_year, month) for name_year in with_full_year 
        for month in range(1, 13)]

然后按季度编写更复杂的分组功能:

def groupby_quarter(col):
    name, year, month = col.split('_')[-3:]
    quarter = (int(month) - 1) / 3 + 1
    return '{}_{}_Q{}'.format(name, year, quarter)

quarterly_means = df[cols].groupby(groupby_quarter, axis=1).mean()

编辑: 我不知道如何在不知道所有列的情况下从每列中提取月,年和水果,但这不应该很难。您可以从将列转换为系列开始,然后使用字符串方法:

cols = df.columns.to_series()
years = cols.str.extract('.*(\d{4}).*')
months = cols.str.extract('.*_(\d{2})(?!\d).*')

这使用正则表达式查找4位数字,然后使用2位数字后跟不是另一位数字。从示例中可以看出,您还可以按如下方式提取产品名称:

product = cols.str.replace('price_of', '').str.replace(.str.extract('_([a-z]*)_.*')

这假设'price_of'是除产品名称之外的列名称中唯一的小写非数字部分,并且产品名称在任一侧都有下划线。获取产品的另一种方法是初始化一个与列相同长度的数组,然后通过循环遍历产品来填充它(可能没有那么多):

products= np.empty(len(cols), dtype=str)
for product in ['apple', 'orange', 'samsung']: 
    products[col.str.contains(product)] = product

正如Paul H建议的那样,此时最好创建一个多索引:

df.columns = pd.MultiIndex.from_arrays([product, year, month])