I have an entity which is an aggregate root and contains a lot of sub-entities. Basically, loading it from the database and persisting it all is a very expensive operation. Most of the time, I only change small parts of the entity so there really is no need to load and persist the entire entity anyway. I am, however, not sure how to implement this using DDD principles and the repository pattern.

Since you don't want your repository involved with domain behaviour your wouldn't do the following:

repository.ActivateAccount(account);

But you could do this:

account.Activate(repository); // in the Activate method the relevant repository
// persistence method will be invoked.

So you can choose a mechanism you are comfortable with.

But getting back to your repository: I wouldn't do querying. A lightweight query layer can return something as simple as a DataTable for your front-end to consume; else DTOs. This relates to the paging you have going there.

The repository deals only with aggregates roots and not with parts of it. SO I suggest this

interface IRepository {
IAggregateRoot Get(string rootId);
//ISubEntityA Get(string rootId); <- this you get from the AR
//IList<ISubEntityB> Get(string rootId, int offset, int pageSize, out int numPages);
//for the method above I suggest a different repository and model dedicated for view
// ISubEntityB Find(string rootId, some specification to select a single ISubEntityB);
// I can update either the entire aggregate root or an individual sub entity using
// these methods.
void Save(IAggregateRoot root); // repository should know if to insert or update, by comparing to the existing instance, use of an OR\M recommended
// void Update(string rootId, ISubEntityA a); <- this should be handled by the method above
// void Update(string rootId, ISubEntityB b); <- this too
}