提问人:MapPeddler 提问时间:12/22/2017 最后编辑:MapPeddler 更新时间:1/4/2018 访问量:1731
从旧 DataFrame 中的行切片追加或创建 DataFrame
Appending or creating dataframe from row slices from old dataframe
问:
我在数据框中有一个表,其中年份列范围为 2001-2018,单元格值范围为 1-9。我正在尝试遍历我的原始数据帧,对于每条记录/行,在最近出现的“9”之后附加该行的所有值。有一些条件要求,但我遇到的问题的症结在于将切片行放入可以导出的新数据帧中。它目前在 80,000 条记录上运行,但只完成了 8,000 条记录,因此效率相当低下。我也非常有信心它不会保留整行,而是将每行的最后一个值设置为新数据帧中的所有单元格值。
这是我的数据帧作为字典的输出:
{2001L: {0: nan, 1: nan, 2: nan, 3: nan, 4: nan},
2002L: {0: 8.0, 1: nan, 2: nan, 3: nan, 4: nan},
2003L: {0: nan, 1: 8.0, 2: 7.0, 3: 8.0, 4: 8.0},
2004L: {0: nan, 1: nan, 2: 8.0, 3: 6.0, 4: 8.0},
2005L: {0: 8.0, 1: 8.0, 2: nan, 3: nan, 4: nan},
2006L: {0: nan, 1: 8.0, 2: nan, 3: 8.0, 4: 9.0},
2007L: {0: nan, 1: 7.0, 2: nan, 3: nan, 4: nan},
2008L: {0: 8.0, 1: 8.0, 2: nan, 3: 8.5, 4: 8.0},
2009L: {0: nan, 1: 8.0, 2: nan, 3: 8.0, 4: 8.0},
2010L: {0: nan, 1: 8.0, 2: 8.0, 3: 8.0, 4: 8.0},
2011L: {0: nan, 1: 8.0, 2: nan, 3: 8.0, 4: 8.0},
2012L: {0: nan, 1: 8.0, 2: nan, 3: 8.0, 4: 8.0},
2013L: {0: nan, 1: 7.0, 2: nan, 3: 8.0, 4: 8.0},
2014L: {0: nan, 1: 7.0, 2: nan, 3: 8.0, 4: 8.0},
2015L: {0: nan, 1: 8.0, 2: nan, 3: nan, 4: nan},
2016L: {0: 8.0, 1: 9.0, 2: nan, 3: 7.0, 4: 8.0},
2017L: {0: nan, 1: 9.0, 2: nan, 3: 7.0, 4: 8.0},
2018L: {0: nan, 1: nan, 2: nan, 3: 7.0, 4: 9.0},
'SegmentID': {0: 15, 1: 16, 2: 17, 3: 18, 4: 19},
'index': {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}}
这是我尝试作为字典接收的输出。
{'Year0': {0: 9, 1: 9, 2: 9},
'Year1': {0: 9.0, 1: nan, 2: 9.0},
'Year2': {0:None, 1: None, 2: None},
'index': {0: 5, 1: 7, 2: 8}}
这是我试图解决这个问题的代码。
for row in df_ratings_pivot.itertuples():
for i in range(len(df_ratings_pivot.columns)):
if row[i] == 9 and row[i-1] <=7 and row[i-2] <= 7:
for j in range(0,len(df_ratings_pivot.columns)-i):
for k in range(i,len(df_ratings_pivot.columns)):
df_new.set_value(row[0],'Year'+str(j),row[k])
print row, j, row[k]
谢谢!
编辑嗨,伊恩,这是我用来修改数据帧的代码。它和你的非常相似。我能看到的唯一区别是,我正在重新索引 df 以将 segID 放在字段列表的末尾,因此它不会影响切片
df_ratings_pivot
df2 = df_ratings_pivot.loc[df_ratings_pivot[df_ratings_pivot ==9].dropna(how = 'all').index]
df2 = df2.reset_index()
cols = df2.columns.tolist()
cols.insert(20, cols.pop(cols.index('SegmentID')))
df2 = df2.reindex(columns=cols)
df2
df2 = df2.astype(str)
df3 = df2.loc[:, df2.max().idxmax():]
df3
我刚刚注意到 idxmax 的错别字。所以我修复了它并且代码有效,但我现在只拉动最后一个 segmentID 列,没有别的。我想这是有道理的,因为您的代码最初没有考虑位于 df 末尾的具有如此高值的 segID 字段。有没有办法在不弄乱切片的情况下保留 SegmentID?
编辑 2
好的,所以我做了你的改变,这是我的屏幕截图形式的结果,希望能加快这个过程。第一个屏幕截图是我将 DF 转换为可由您的代码修改的格式。第二部分是代码的结果。
从一开始,似乎就有额外的信息被拉进来了。例如,记录 1 应该从 2016 年开始,因为这是第一次出现 9。第一个记录应该只有 2016 年和 2017 年的 2 个值。也许我应该创建一个新的数据帧并附加到其中,而不是从现有数据帧中切片?
我的最终目标数据帧将从某个任意的 Year0 字段名称开始,该字段名称将填充一堆 9。第 0 年之后的所有内容都将使用相应的记录值进行填充。.在最初的 9.因此,对于记录 1、2 和 3,它将是:
{Year0: {0: 9, 1: 9, 2: 9, ...},
Year1: {0: 9, 1:nan,2:9, ...},
Year2: {0: nan, 1: 8, 2: nan, ...},}
答:
只是为了在这里得到答案并希望能更多地理解这个问题,这里有一种方法可以使用您的示例数据删除没有 9 的行并删除前 9 之前的所有列。
# make data into pd.DataFrame
df = pd.DataFrame.from_dict(data)
# make all columns strings
df.columns = df.columns.astype(str)
# sort the columns
df.sort_index(axis = 1, inplace = True)
# drop index
df.drop('index', axis = 1, inplace = True)
df
# remove 'SegmentID' for now, join later
df1 = df[df.columns.tolist()[:-1]]
# drop rows without a 9
df2 = df1.loc[df1[df1 == 9].dropna(how = 'all').index]
df2
# drop first columns before first occurrence of 9
df3 = df2.loc[:, df2.max().idxmax():]
# store index
idx = df3.index
# loop through columns to replace values != 9 with NaN preceeding first 9
for col in df3.columns:
# remove index with 9
idx = idx.drop(df3[df3[col] == 9].index)
# fill values != 9 with NaN
df3.loc[idx, col] = np.NaN
# break out of loop when index runs out
if len(idx) == 0:
break
# join SegmentID back in
df3.join(df.SegmentID)
顺便说一句,我正在使用 Python 3.5.2、Pandas 0.20.3,以防您遇到语法错误。我还转换了您的年份列,以便我可以对列进行切片。str
评论
上一个:Python 中的循环切片
下一个:切片生成时给出的元组的元组
评论
df.to_dict()
df