(实际输入CSV正常以逗号分隔;我只是将我的想法显示为表格以便于查看。)
这是我想用Python 2.7做的一个例子(Pandas如果它更好/更容易,但我也喜欢学习python逻辑和pandas跳过很多,虽然我可能必须学习这样的东西):
这
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行中遗漏了From
,则To
看起来会相同,而不会产生“Email2”列。另外,虽然列的顺序无关紧要(我使用它来填充需要CSV输入的数据库),但编号必须匹配!也就是说,对于任何给定的名称,例如Foo高于:60美元,物品,280和N都必须在标有“[OrigName] 2”的列中 - 并且当任何给定标签的column1为空时,不应填充Column2。
这应该很简单,但为了完整起见,我还需要一个列来填充填充的文本列(例如,整数列“文本数”),另一个列加上标记为“Price”的数字“免费“(例如,”自由文本数“)。
非常感谢您的帮助 - 我已经为我将从中学到的东西感到兴奋,并且欢迎进一步阅读资源!
答案 0 :(得分: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
答案 1 :(得分: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
这里只有一些技巧。一个是ranks
,我们用它来决定一个值应该去哪一列。我们reset_index()
使用该方法在"index"
上获取名为[0, 1, .., 5]
的列groupby
,Name
,然后rank
“first”,简单地表示1对应于组中看到的第一个值,2表示第二个值,依此类推。
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
然后我们使用identity函数作为聚合函数创建一个数据透视表,因为我们只是重新整形。这会为列索引生成DataFrame
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
我ffill()
的情况,并添加额外的摘要列,我要么使用柱状groupby
,要么只使用列上的listcomp。但这些都非常简单,而上述内容有点棘手。