【问题标题】:How to pivot a column into diffrent categories in python如何在python中将列旋转到不同的类别
【发布时间】:2015-07-20 19:28:38
【问题描述】:

我有一个管道文本文件,其结构如下所示:

seatle|washington|13|35|1|NW|2005-05-10                 
sanfransisco|california|13|31|1|W|2005-05-10            
chicago|illinois|10|33|1|C|2005-05-10               
newyorkcity|newyork|9|32|2|E|2005-05-10                 
DC|DC|9|30|4|E|2005-05-10               
miami|florida|9|20|4|SE|2005-05-10              
dallas|texas|12|22|2|S|2005-05-10    

在上面的示例中,5th 列是一个类别编号。数据集中可以有n 的类别数量(在上面的示例中有3 类别-124,但数量可能会有所不同)。现在我想要从input file 读取数据,根据column 5 中的类别旋转column 34,并创建另一个output file,其结构应如下所示:

column 1|column 2|column 6|column 7|column3_catgory1|column3_catgory2|column3_catgory3|....|column4_catgory1|column4_catgory2|column4_catgory3|...          

因此输出文件应该有来自输入文件column 1,column 2,column 6,column 7的数据,然后是column 3的数据,基于column 5的值在相应的输出列中提到接下来是基于column 5的值在相应输出列中提到的column 4的数据。因此对于上述示例输入,输出文件应如下所示:

column 1    |column 2  |column 6|column 7  |column3_1|column3_2|column3_4|column4_1|column4_2|column4_4
seatle      |washington|NW      |2005-05-10|13       |         |         |35       |         |                       
sanfransisco|california|W       |2005-05-10|13       |         |         |31       |         |            
chicago     |illinois  |C       |2005-05-10|10       |         |         |33       |         |               
newyorkcity |newyork   |E       |2005-05-10|         |9        |         |         |32       |                 
DC          |DC        |E       |2005-05-10|         |         |9        |         |         |30

如您所见,由于存在3 类别,因此输入的column 34 被转为输出中的三个不同列,并根据类别在相应列中提及值。例如,对于带有seatle 的行,因为类别是1,所以column 3column 4 的值分别在column3_1column4_1 中与其他第3 列类别值(column3_2 & column3_4) 和第 4 列类别值 (column4_2 & column4_4) 为空。

现在这是我编写的用于读取管道文件并确定有多少类别的代码,但我无法在此之前继续。

    category = []

    read = open('file1.txt', 'r')

    for line in read:
        fields = line.split('|')
        if fields[4] not in category:
            category.append(fields[4])
    category = map(int, category) #converts the category value to int for sorting
    category.sort()

谁能帮助我如何在这之前进行并适当地调整价值观?

注意:即使输入文件中没有header,我想在输出文件中添加标题,就像我在上面的示例输出结构中显示的那样。同样在输出中,我不希望两列值之间有任何额外的空格,正如我在示例输入的示例输出数据中所示。我特意添加了这些空格,以便更轻松地查看我想要的内容。

【问题讨论】:

  • 我会查看pandas。您可以使用pandas.read_tables 将输出文件加载到pandas.DataFrame,传递sep='|'。有很多选项可用于处理标题等。然后应该很容易拆分数据帧、添加列等。另外,请查看 pandas.pydata.org/pandas-docs/stable/merging.html ,您也许可以使用 @987654359 完成您想要做的事情@ 功能。你可能会花很多时间来编写自己的数据库代码,但如果你打算在 python 中做严肃的数据库工作,请使用 pandas
  • @dermen 它不是数据库工作。输入是一个文件,输出也是一个文件。我想要的只是根据输入文件中的column 5 值将输入数据的column 3column 4 旋转到输出中的不同列
  • 我明白了。尽管如此,您正在使用列、行样式数据,为此,pandas 有一些方便的工具,我将发布一个示例。

标签: python pivot


【解决方案1】:

我拿了你的例子,稍微修改了一下,然后添加到代码中以生成输出文件。也许不是最优雅的方法,但似乎可以使用您的示例数据。

category = []
columns = []

read = open('file1.txt', 'r')

for line in read:
    fields = line.split('|')
    columns.append(fields)
    category.append(int(fields[4]))
category = sorted(set(category))
print(category)

for line in columns:
    print(line)

out = open('fileout.txt', 'w')

out.write('column 1|column 2|column 6|column 7|')
for val in category:
    out.write('column3_{0}|'.format(val))
for val in category:
    out.write('column4_{0}|'.format(val))
out.write('\n')

for line in columns:
    out.write('{0}|{1}|{2}|{3}|'.format(line[0], line[1], line[5], line[6].rstrip()))
    for val in category:
        if int(line[4]) == val:
            out.write('{0}|'.format(line[2]))
        else:
            out.write(' |')
    for val in category:
        if int(line[4]) == val:
            out.write('{0}|'.format(line[3]))
        else:
            out.write(' |')                    
    out.write('\n')

【讨论】:

  • 我没有尝试过你的版本,但它会处理动态的类别数量吗?我的意思是在我的示例帖子中,尽管第 5 列值中有 3 个类别,但并非每次都如此。因此,如果有 5 个类别,那么在第 1、2、6、7 列之后,我们应该有第 3 列的 5 列和第 4 列的 5 列。每次运行时类别都会有所不同
  • 是的,它应该适用于第 5 列中的许多唯一值。我没有测试它,但我不明白为什么它不会。
【解决方案2】:

这是一个使用pandas.DataFrame的简单解决方案:

col_names = [ 'col_%d'%(x+1) for x in xrange(7)] # make up some names
df = pandas.read_table( 'test.txt', sep='|' , names=col_names ) # read in the data

df
#          col_1       col_2  col_3  col_4  col_5 col_6       col_7
#0        seatle  washington     13     35      1    NW  2005-05-10
#1  sanfransisco  california     13     31      1     W  2005-05-10
#2       chicago    illinois     10     33      1     C  2005-05-10
#3   newyorkcity     newyork      9     32      2     E  2005-05-10
#4            DC          DC      9     30      4     E  2005-05-10
#5         miami     florida      9     20      4    SE  2005-05-10
#6        dallas       texas     12     22      2     S  2005-05-10

这里我们获取第 5 列中的唯一值:

u_vals = pandas.unique( df.col_5 ) # the unique values in column 5
u_dfs = [ df.query( 'col_5 == %d'%x) for x in u_vals ] # the sub-dataframes corresponding to each unique value of column 5

u_dfs[0] # for example
#          col_1       col_2  col_3  col_4  col_5 col_6       col_7
#0        seatle  washington     13     35      1    NW  2005-05-10
#1  sanfransisco  california     13     31      1     W  2005-05-10
#2       chicago    illinois     10     33      1     C  2005-05-10

接下来,通过重命名第 3 列和第 4 列以及删除第 5 列,准备合并数据帧(它可能会引发警告,因为我们正在修改原始 df 对象,但忽略)

# now rename the column 3 and 4 corresponding to the unique vals found in column 5
for uval, udf in zip( u_vals, u_dfs ):
    udf.rename( columns={'col_3':'col_3_%d'%uval, 'col_4':'col_4_%d'%uval}, inplace=True)
    udf.drop( labels='col_5', axis=1 , inplace=True) # drop column 5

接下来,merge the dataframes

result = reduce(lambda left,right: pandas.merge(left,right,on=[ 'col_1', 'col_2', 'col_6', 'col_7'], how='outer'), u_dfs)
result
#              col_1       col_2  col_3_1  col_4_1 col_6       col_7  col_3_2  \
#0        seatle  washington       13       35    NW  2005-05-10      NaN   
#1  sanfransisco  california       13       31     W  2005-05-10      NaN   
#2       chicago    illinois       10       33     C  2005-05-10      NaN   
#3   newyorkcity     newyork      NaN      NaN     E  2005-05-10        9   
#4        dallas       texas      NaN      NaN     S  2005-05-10       12   
#5            DC          DC      NaN      NaN     E  2005-05-10      NaN   
#6         miami     florida      NaN      NaN    SE  2005-05-10      NaN   

#   col_4_2  col_3_4  col_4_4  
#0      NaN      NaN      NaN  
#1      NaN      NaN      NaN  
#2      NaN      NaN      NaN  
#3       32      NaN      NaN  
#4       22      NaN      NaN  
#5      NaN        9       30  
#6      NaN        9       20     

现在我们可以重新排列列以确保它们处于所需的顺序并保存

cols_out = ['col_1', 'col_2', 'col_6', 'col_7'] + ['col_3_%d'%x for x in u_vals] + ['col_4_%d'%x for x in u_vals] # do this however you like
print ( cols_out) 
#['col_1', 'col_2', 'col_6', 'col_7', 'col_3_1', 'col_3_2', 'col_3_4', 'col_4_1', 'col_4_2', 'col_4_4']
result.to_csv('result.txt', sep='|', na_rep='NA', index=False, columns=cols_out) # save the result as a new txt file, format however you like

现在result.txt 看起来像

col_1|col_2|col_6|col_7|col_3_1|col_3_2|col_3_4|col_4_1|col_4_2|col_4_4
seatle|washington|NW|2005-05-10|13.0|NA|NA|35.0|NA|NA
sanfransisco|california|W|2005-05-10|13.0|NA|NA|31.0|NA|NA
chicago|illinois|C|2005-05-10|10.0|NA|NA|33.0|NA|NA
newyorkcity|newyork|E|2005-05-10|NA|9.0|NA|NA|32.0|NA
dallas|texas|S|2005-05-10|NA|12.0|NA|NA|22.0|NA
DC|DC|E|2005-05-10|NA|NA|9.0|NA|NA|30.0
miami|florida|SE|2005-05-10|NA|NA|9.0|NA|NA|20.0

【讨论】:

  • 您的输出中的col3_1col4_1 与其他第3 列和第5 列类别分开。顺序应为第1、2、6、7 列,然后是所有第3 列类别,然后是所有列 4 个类别
  • 您可以通过将columns= 参数传递给to_csv 来指定输出文件中的列顺序
  • 顺便说一句,如果列有标题,那么为什么顺序很重要。我认为仅当您没有在标题中指定列名时,顺序才重要。但话又说回来,我不知道您将输出用于什么。无论如何,我更新了答案以包含您想要的列顺序
猜你喜欢
  • 1970-01-01
  • 2011-03-08
  • 1970-01-01
  • 2018-09-03
  • 2019-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多