我正在使用Django编写一个应用程序,遇到了一个问题。我有如下型号:
class Feature(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
feature_name = models.CharField(max_length=300)
feature_code = models.CharField(max_length=50, unique=True)
feature_predictable = models.BooleanField(default=False)
def __str__(self):
return self.feature_name
def breed_name_based_upload_to(instance, filename):
return "breeds/{0}/{1}".format(instance.breed_name, filename)
class Breed(models.Model):
breed_name = models.CharField(max_length=300)
breed_features = models.ManyToManyField(Feature)
breed_image = models.ImageField(default='no_image.png', upload_to=breed_name_based_upload_to)
breed_visible = models.BooleanField(default=True)
def __str__(self):
return self.breed_name
class FeatureValue(models.Model):
breed = models.ForeignKey(Breed, on_delete=models.CASCADE)
feature = models.ForeignKey(Feature, on_delete=models.CASCADE)
feature_value = IntegerRangeField(min_value=1, max_value=3, default=1)
class Meta:
unique_together = ('breed', 'feature')
在"Feature"模型中,我有3条记录的Feature_code具有值,例如"value1"、"value2"one_answers"value3"。在"品种"模型中,我还有3个记录,每个记录都为"特征"模型中的每个记录分配了值(我使用FeatureValue模型来分配值(。
现在我需要使用Breed模型来创建一个看起来像这样的DataFrame:
id breed_name value1 value2 value3
0 name1 2 1 3
1 name2 1 2 2
2 name3 3 3 3
目前,使用此代码:
dataframe = pandas.DataFrame().from_records(list(
Breed.objects.all().values(
'id',
'breed_name',
'featurevalue__feature_value'
)
))
我设法实现了这样的目标:
id breed_name featurevalue__feature_value
0 name1 2
0 name1 1
0 name1 3
1 name2 1
1 name2 2
1 name2 2
2 name3 3
2 name3 3
2 name3 3
我该怎么修?
如果我们从您的示例数据帧开始。
您可以枚举每组breed_name
值中的行。
>>> df["pos"] = df.groupby("breed_name").cumcount()
>>> df["pos"] = "value" + df["pos"].astype("str")
>>> df
id breed_name featurevalue__feature_value pos
0 0 name1 2 value0
1 0 name1 1 value1
2 0 name1 3 value2
3 1 name2 1 value0
4 1 name2 2 value1
5 1 name2 2 value2
6 2 name3 3 value0
7 2 name3 3 value1
8 2 name3 3 value2
然后透视数据帧,删除额外级别的列索引并重置行索引。
>>> df2 = df.pivot(columns="pos", index=["id", "breed_name"])
>>> df2
featurevalue__feature_value
pos value0 value1 value2
id breed_name
0 name1 2 1 3
1 name2 1 2 2
2 name3 3 3 3
>>> df2 = df2.droplevel(0, axis=1).reset_index()
>>> df2
pos id breed_name value0 value1 value2
0 0 name1 2 1 3
1 1 name2 1 2 2
2 2 name3 3 3 3
您可以按如下方式执行:
df2 = df.groupby(['id','breed_name'], as_index=False).agg(list)
max_values = df2.featurevalue__feature_value.str.len().max()
df2[['value'+str(i+1) for i in range(max_values)]] = df2.featurevalue__feature_value.apply(pd.Series)
df2.drop('featurevalue__feature_value', axis=1, inplace=True)
输出:
>>> df2
id breed_name value1 value2 value3
0 0 name1 2 1 3
1 1 name2 1 2 2
2 2 name3 3 3 3
解释:
- 第一个
groupby
id,breed_name列,并将结果聚合为list
- 然后找到所需的
max
个值列,并将聚合列表值转换为featurevalue__feature_value列以使用pandas.Series
分隔值的列 - 最后删除featurevalue__feature_value列