1

(实际输入的 CSV 正常以逗号分隔;我只是将我的想法显示为表格以便于查看。)

这是我想使用 Python 2.7 做的一个例子(如果它更好/更容易,熊猫,但我也喜欢学习 python 逻辑,熊猫跳过了很多,尽管我可能不得不为这样的东西学习它):

Price    Name    Text      Number    Choice   URL         Email
$40      Foo     Stuff     560       Y        www.a.com   a@a.com
$60      Foo     Things    280       N        www.a.com   a@a.com
$20      Foo     Other     120       Y        www.a.com   a@a.com
$25      John    Gals      1222      N        www.b.com   b@b.com
$100     Bar     Dudes     999       Y        www.c.com   c@c.com
$250     Bar     Guys      200       Y        www.c.com   c@c.com

Name    Price1    Price2   Price3   Text1    Text2    Text3    Number1    Number2    Number3    Choice1    Choice2    Choice3    URL         Email
Foo     $40       $60      $20      Stuff    Things   Other    560        280        120        Y          N          Y          www.a.com   a@a.com
John    $25                         Gals                       1222                             N                                www.b.com   b@b.com
Bar     $100      $250              Dudes    Guys              999        200                   Y          Y                     www.c.com   c@c.com

列的顺序无关紧要,但我想按名称列作为规则进行组合。(希望我做对了,因为这个例子很痛苦!)

为了获得额外的功劳,如果单元格为空白,我很想阻止一个单元格填充新列:例如,如果上面a@a.com第 2 行缺少,看起来会相同,而不是生成“Email2”列。此外,虽然列的顺序无关紧要(我使用它来填充需要 CSV 输入的数据库),但编号必须匹配!也就是说,对于任何给定的名称,例如上面的 Foo:$60、Things、280 和 N 都必须在标记为“[OrigName]2”的列中 - 并且对于任何给定标签,当 column1 为空白时,不应填充 Column2。FromTo

这应该很容易,但为了完整起见,我还需要一列将填充的文本列(例如整数列“文本数量”)相加,另一列将标记为“免费”的“价格”的数量相加(例如,“自由文本的数量”)。

非常感谢您的帮助 - 我已经为我将从中学到的东西感到兴奋,并且随时欢迎进一步阅读资源!

4

2 回答 2

2

在 [252] 中:

import pandas as pd
import io

f = io.BytesIO("""Price    Name    Text      Number    Choice   URL         Email
40      Foo     Stuff     560       Y        www.a.com   a@a.com
60      Foo     Things    280       N        www.a.com   
20      Foo     Other     120       Y        www.a.com   a@a.com
25      John    Gals      1222      N        www.b.com   b@b.com
100     Bar     Dudes     999       Y        www.c.com   c@c.com
250     Bar     Guys      200       Y        www.c.com   c@c.com""")

df = pd.read_csv(f, delim_whitespace=True)
print df

输出:

   Price  Name    Text  Number Choice        URL    Email
0     40   Foo   Stuff     560      Y  www.a.com  a@a.com
1     60   Foo  Things     280      N  www.a.com      NaN
2     20   Foo   Other     120      Y  www.a.com  a@a.com
3     25  John    Gals    1222      N  www.b.com  b@b.com
4    100   Bar   Dudes     999      Y  www.c.com  c@c.com
5    250   Bar    Guys     200      Y  www.c.com  c@c.com

在 [253] 中:

split_columns = ["Price", "Text", "Number", "Choice"]

def split_func(df):
    return df.set_index(np.arange(1, df.shape[0]+1))

df2 = df[split_columns].groupby(df.Name).apply(split_func).unstack()
df2.columns = [name+str(i) for name, i in df2.columns]
print df2

输出:

      Price1  Price2  Price3  Text1   Text2  Text3  Number1  Number2  Number3  \
Name                                                                            
Bar      100     250     NaN  Dudes    Guys    NaN      999      200      NaN   
Foo       40      60      20  Stuff  Things  Other      560      280      120   
John      25     NaN     NaN   Gals     NaN    NaN     1222      NaN      NaN   

     Choice1 Choice2 Choice3  
Name                          
Bar        Y       Y     NaN  
Foo        Y       N       Y  
John       N     NaN     NaN  

在 [245] 中:

unique_columns = ["URL", "Email"]

def unique_func(s):
    return s.dropna().unique()[0]

df3 = df[unique_columns].groupby(df.Name).agg(unique_func)
print df3

输出:

            URL    Email
Name                    
Bar   www.c.com  c@c.com
Foo   www.a.com  a@a.com
John  www.b.com  b@b.com

在 [246] 中:

print pd.merge(df2, df3, left_index=True, right_index=True)

输出:

      Price1  Price2  Price3  Text1   Text2  Text3  Number1  Number2  Number3  \
Name                                                                            
Bar      100     250     NaN  Dudes    Guys    NaN      999      200      NaN   
Foo       40      60      20  Stuff  Things  Other      560      280      120   
John      25     NaN     NaN   Gals     NaN    NaN     1222      NaN      NaN   

     Choice1 Choice2 Choice3        URL    Email  
Name                                              
Bar        Y       Y     NaN  www.c.com  c@c.com  
Foo        Y       N       Y  www.a.com  a@a.com  
John       N     NaN     NaN  www.b.com  b@b.com  
于 2013-11-06T03:29:38.723 回答
1

使用pandas,您可以查看您想要的损坏的数据透视表。你可以得到大部分的方式来做类似的事情

import pandas as pd
df = pd.read_csv("stuff.dat",sep=r"\s+")
df["ranks"] = df.reset_index().groupby("Name")["index"].rank("first")
df2 = df.pivot_table(rows=["Name", "URL", "Email"],
                     cols="ranks",
                     aggfunc=lambda x: x, fill_value='')
df2.columns = [c[0] + str(int(c[1])) for c in df2.columns.get_values()]
df2 = df2.reset_index()

产生

>>> print df2.to_string()
   Name        URL    Email Price1 Price2 Price3  Text1   Text2  Text3 Number1 Number2 Number3 Choice1 Choice2 Choice3
0   Bar  www.c.com  c@c.com   $100   $250         Dudes    Guys            999     200               Y       Y        
1   Foo  www.a.com  a@a.com    $40    $60    $20  Stuff  Things  Other     560     280     120       Y       N       Y
2  John  www.b.com  b@b.com    $25                 Gals                   1222                       N                

这里只有一些技巧。一个是 getting ranks,我们用它来决定一个值应该去哪一列。我们reset_index()得到一个名为 的列,在 上,然后每个组使用“first”方法,这意味着 1 对应于组中看到的第一个值,2 对应于第二个,依此类推"index"[0, 1, .., 5]groupbyNamerank

IOW,我们建立一个ranks看起来像的列

>>> df[["Name", "ranks"]]
   Name  ranks
0   Foo      1
1   Foo      2
2   Foo      3
3  John      1
4   Bar      1
5   Bar      2

然后我们制作一个数据透视表,使用恒等函数作为聚合函数,因为我们只是在重塑。这会为列索引生成一个DataFrame带有 a的:MultiIndex

                       Price              Text                Number           Choice      
ranks                      1     2    3      1       2      3      1    2    3      1  2  3
Name URL       Email                                                                       
Bar  www.c.com c@c.com  $100  $250       Dudes    Guys           999  200           Y  Y   
Foo  www.a.com a@a.com   $40   $60  $20  Stuff  Things  Other    560  280  120      Y  N  Y
John www.b.com b@b.com   $25              Gals                  1222                N      

(注意:如果这是我想要的结构,而不是展平列,这实际上是我可能离开的方式。)

最后我们折叠列:

>>> df2.columns
MultiIndex(levels=[[u'Price', u'Text', u'Number', u'Choice'], [1.0, 2.0, 3.0]],
           labels=[[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]],
           names=[None, u'ranks'])
>>> df2.columns.get_values()
array([('Price', 1.0), ('Price', 2.0), ('Price', 3.0), ('Text', 1.0),
       ('Text', 2.0), ('Text', 3.0), ('Number', 1.0), ('Number', 2.0),
       ('Number', 3.0), ('Choice', 1.0), ('Choice', 2.0), ('Choice', 3.0)], dtype=object)

为了处理基于名称的缺失情况,并添加额外的汇总列,email我要么使用列式,要么仅在列上使用 listcomp。但是这些非常简单,而上面的则有点棘手。 ffill()groupby

于 2013-11-06T03:47:32.437 回答